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/testand route template include__tenantWhich mean you need add
__tenantto 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
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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!
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
hi
Add a
AddTenantToRouteclass 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(); //...Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

