Hello, I need more information about RouteTenantResolveContributor, but I couldn't find it in your documentation. Would it be possible for you to share an example with me? How can I configure it and, for example, set up Swagger routing? Thank you for your help.
10 Answer(s)
-
0
hi
If your current url is
https://localhost:44303/Weather/test
and route template include__tenant
Which mean you need add
__tenant
to your route template[Route("[Controller]/{__tenant}")] public class WeatherController : MyProjectNameController { [HttpGet] public IActionResult GetWeather() { return Ok($"Current tenant is {CurrentTenant.Name}"); }
See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing
-
0
Hi,
I need your support on a few topics:
1-Is there a centralized and efficient way to add the {__tenant} parameter to automatically generated endpoint routes?
2-How can I include the {__tenant} parameter in the endpoints displayed in Swagger UI?
3-Is there any example or documentation available regarding the necessary configuration for AuthServer and ApiHost projects to support this setup?
I’d really appreciate your help. Thank you!
-
0
hi
What is the final URL format you expect?
Like this? https://localhost:44303/tenantname/api/abp
-
0
Yes exactly like this,https://localhost:44303/tenantname/api/abp
https://localhost:44303/tenantname/swagger/index.html https://localhost:44303/tenantname/Account/Login
-
0
hi
I will find a way.
-
0
hi
Add a
AddTenantToRoute
class then add it to aspnet core system.using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Routing; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.MultiTenancy; namespace MyCompanyName.MyProjectName.Web; public class AddTenantToRoute : IPageRouteModelConvention, IApplicationModelConvention { public void Apply(PageRouteModel model) { var selectorCount = model.Selectors.Count; var selectorModels = new List<SelectorModel>(); for (var i = 0; i < selectorCount; i++) { var selector = model.Selectors[i]; selectorModels.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[a-zA-Z0-9]+$)}", selector.AttributeRouteModel!.Template!.RemovePreFix("/")) } }); } foreach (var selectorModel in selectorModels) { model.Selectors.Add(selectorModel); } } public void Apply(ApplicationModel application) { var controllers = application.Controllers; foreach (var controller in controllers) { var selector = controller.Selectors.FirstOrDefault(); if (selector == null || selector.AttributeRouteModel == null) { controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", controller.ControllerName) } }); controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = controller.ControllerName } }); } else { var template = selector.AttributeRouteModel?.Template; template = template.IsNullOrWhiteSpace() ? "{__tenant:regex(^[[a-zA-Z0-9]]+$)}" : AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", template.RemovePreFix("/")); controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = template } }); } } } } public class MyRouteTenantResolveContributor : RouteTenantResolveContributor { public const string ContributorName = "MyRoute"; public override string Name => ContributorName; protected override Task<string?> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext) { var tenantId = httpContext.GetRouteValue(context.GetAbpAspNetCoreMultiTenancyOptions().TenantKey) ?? httpContext.Request.PathBase.ToString(); var tenantIdStr = tenantId?.ToString()?.RemovePreFix("/"); return Task.FromResult(!tenantIdStr.IsNullOrWhiteSpace() ? Convert.ToString(tenantIdStr) : null); } }
public override void ConfigureServices(ServiceConfigurationContext context) { //... PostConfigure<RazorPagesOptions>(options => { options.Conventions.Add(new AddTenantToRoute()); }); PostConfigure<MvcOptions>(options => { options.Conventions.Add(new AddTenantToRoute()); }); context.Services.ConfigureApplicationCookie(x => { x.Cookie.Path = "/"; }); Configure<AbpTenantResolveOptions>(options => { options.TenantResolvers.Add(new MyRouteTenantResolveContributor()); }); //... }
public override void OnApplicationInitialization(ApplicationInitializationContext context) { //... app.Use(async (httpContext, next) => { var tenantMatch = Regex.Match(httpContext.Request.Path, "^/([^/.]+)(?:/.*)?$"); if (tenantMatch.Groups.Count > 1 && !string.IsNullOrEmpty(tenantMatch.Groups[1].Value)) { var tenantName = tenantMatch.Groups[1].Value; if (!tenantName.IsNullOrWhiteSpace()) { var tenantStore = httpContext.RequestServices.GetRequiredService<ITenantStore>(); var tenantNormalizer = httpContext.RequestServices.GetRequiredService<ITenantNormalizer>(); var tenantInfo = await tenantStore.FindAsync(tenantNormalizer.NormalizeName(tenantName)!); if (tenantInfo != null) { if (httpContext.Request.Path.StartsWithSegments(new PathString(tenantName.EnsureStartsWith('/')), out var matchedPath, out var remainingPath)) { var originalPath = httpContext.Request.Path; var originalPathBase = httpContext.Request.PathBase; httpContext.Request.Path = remainingPath; httpContext.Request.PathBase = originalPathBase.Add(matchedPath); try { await next(httpContext); } finally { httpContext.Request.Path = originalPath; httpContext.Request.PathBase = originalPathBase; } return; } } } } await next(httpContext); }); app.UseRouting(); app.MapAbpStaticAssets(); //...
-
0
Thanks for replying, I will try and let you inform
-
0
sure
-
0
Hi, Thanks for your help, it worked as expected.
-
0
Good news. I will also share a community article to explain this. https://github.com/abpframework/abp/issues/22919
Thanks.