Finbuckle / Finbuckle.MultiTenant

Finbuckle.MultiTenant is an open-source multitenancy middleware library for .NET. It enables tenant resolution, per-tenant app behavior, and per-tenant data isolation.
https://www.finbuckle.com/multitenant
Apache License 2.0
1.33k stars 264 forks source link

Finbuckle BasePathStrategy overwritting existing base path (IIS) (Blazor Server-side app) #597

Closed Romanky closed 2 years ago

Romanky commented 2 years ago

I'm using WithBasePathStrategy() in a Blazor Server-side application deployed on IIS.

When the base path should be extended by the tenant it is replaced instead:

The problem is that the value in httpContext.PathBase is set to /tenentId but I expect it to be /mybasePath/tenentId

could be related to #501

Version Infos: Finbuckle.MultiTenant.AspNetCore version: 6.8.1 Dot Net version: 6.0

AndrewTriesToCode commented 2 years ago

Thanks @Romanky Just to be clear, you didn't have the option enabled in WithBasePathStrategy for the behavior turned on did you?

        ...WithBasePathStrategy(options =>
        {
          options.RebaseAspNetCorePathBase = true;
        })...
Romanky commented 2 years ago

Thank you for the quick reply @AndrewTriesToCode Yes I enabled the RebaseAspNetCorePathBase - I'm sorry that I forgot to mention that 🙈

AndrewTriesToCode commented 2 years ago

Hi, so unless I am misunderstanding -- if you set that rebase option to false it will behave as you want, right?

Romanky commented 2 years ago

No, what I want to say is that the RebaseAspNetCorePathBase doesn't work properly when there is already a Request.PathBase defined. Might be an IIS specific problem?!

Your example in the docu works as expected:

For example, a request to https://mydomain.com/mytenant/mypath by default has a Request.PathBase of / and a Request.Path of /mytenant/mypath. Setting this option will adjust these values to /mytenant and /mypath respectively when a tenant is successfully resolved with the BasePathStrategy.

The example adapted to my needs:

A request to https://mydomain.com/mybase/mytenant/mypath by default has a Request.PathBase of /mybase and a Request.Path of /mytenant/mypath. Setting this option should adjust these values to /mybase/mytenant and /mypath respectively when a tenant is successfully resolved with the BasePathStrategy

...but instead the Request.PathBase is overwritten to /mytenant (Request.Path is correctly set to /mypath)

This is how the IIS settings would look like: image

AndrewTriesToCode commented 2 years ago

Yep, you are right. Thanks for the detailed response!

Your fix looks good. Do you mind adding a unit test at Finbuckle.MultiTenant.AspNetCore.Test/Strategies/BasePathStrategyShould to incorporate this in your PR? The test code would be:

        [Fact]
        public async void AppendTenantToExistingBase()
        {

            var services = new ServiceCollection();
            services.AddOptions().AddMultiTenant<TenantInfo>().WithBasePathStrategy().WithInMemoryStore(options =>
            {
                options.Tenants.Add(new TenantInfo
                {
                    Id = "tenant",
                    Identifier = "tenant",
                    Name = "tenant"
                });
            });
            services.Configure<BasePathStrategyOptions>(options => options.RebaseAspNetCorePathBase = true);
            var serviceProvider = services.BuildServiceProvider();
            var httpContext = CreateHttpContextMock("/tenant/path");
            httpContext.RequestServices = serviceProvider;

            Assert.Equal("/base", httpContext.Request.PathBase);
            Assert.Equal("/tenant/path", httpContext.Request.Path);

            // will trigger OnTenantFound event...
            var resolver = await serviceProvider.GetRequiredService<ITenantResolver>().ResolveAsync(httpContext);

            Assert.Equal("/base/tenant", httpContext.Request.PathBase);
            Assert.Equal("/path", httpContext.Request.Path);
        }