Finbuckle.MultiTenant icon indicating copy to clipboard operation
Finbuckle.MultiTenant copied to clipboard

Blazor server-side sample?

Open win32nipuh opened this issue 5 years ago • 16 comments

It will be very useful to have an example how to use Finbuckle.MultiTenant in a Blazor Web Server. Do you have a plan to create one?

win32nipuh avatar Apr 28 '20 10:04 win32nipuh

hi @win32nipuh

I would like to, but I need to get up-to-date with Blazor and so it probably won't be in the immediate future. There are some decent discussions about it in the closed issues if you haven't found them yet.

AndrewTriesToCode avatar Apr 28 '20 15:04 AndrewTriesToCode

Thanx. I see ok. Andrew could you please take a look at my another question? I need to pass multiple tenants parameters like Connection string to database, S3 connection parameters etc. How I can do it?

win32nipuh avatar Apr 29 '20 07:04 win32nipuh

Hi Andrew, I have created full functional Blazor Server app DataIsolationBlazorSample https://github.com/Oleg26Dev/Finbuckle.MultiTenant/tree/release-6.0.0-dev/samples/ASP.NET%20Core%203/DataIsolationBlazorSample

The pull request is created to the release-6.0.0-dev. Now it uses Finbuckle.MultiTenant project, later it can be replaced with NuGet package. The Blazor sample project is added to samples\ASP.NET Core 3: DataIsolationBlazorSample It is based on the existing DataIsolationSample project with some new features. The example uses multitenant strategies: host and route, which can be managed in appsettings.json. The section:

"TenantStrategy": {
    "RouteStrategy": false,
    "DefaultRoute": "{__tenant__=}/{controller=Home}/{action=Index}",
    "HostTemplate": "__tenant__.*"
  },

When "RouteStrategy": true, the app has three menus Megacorp Tenant Finbuckle Tenant Initech Tenant as in original sample. When "RouteStrategy": false the app has one menu

Current Tenant

and shows the db data for the current tenant.

To test host strategy use one of ways:

  1. Edit Windows hosts file 127.0.0.1 megacorp 127.0.0.1 finbuckle 127.0.0.1 initech

  2. I prefer to use DNS like xip.io https://megacorp.127.0.0.1.xip.io:5001 https://finbuckle.127.0.0.1.xip.io:5001 https://initech.127.0.0.1.xip.io:5001

ZedZipDev avatar May 09 '20 05:05 ZedZipDev

One thing I'm running into here is with blazor server, basepath strategy seems to have issues. On some calls I end up with '_blazor' as the attempted tenant name which causes things to bomb. Has anyone figured this out?

natelaff avatar Sep 21 '20 11:09 natelaff

@natelaff is _blazor actually he base path of the requests or is Blazor modifying the base path? In AddMultiTenant you can specifiy identifiers to ignore, but I'm not sure if that will work. Might have to reimplement your own strategy to handle this odd behavior.

AndrewTriesToCode avatar Sep 21 '20 17:09 AndrewTriesToCode

yeah it seems to be modifying it on its own. i will try with the ignore identifiers, i missed that bit. honestly, after three days about to ditch blazor efforts. the oidc picture there is not good.

natelaff avatar Sep 21 '20 19:09 natelaff

Thanks @Oleg26Dev for the sample code. I'm trying to use it with the nuget instead of direct reference to Finbuckle.MultiTenant project.

To do so I remove the direct reference to Finbuckle.MultiTenant project and instead add the following nugets Finbuckle.MultiTenant Finbuckle.MultiTenant.AspNetCore Finbuckle.MultiTenant.EntityFrameworkCore

but there are a bunch of extensions and related classes that seems to be missed. @AndrewTriesToCode is there an additional nuget that I'm missing or is this something still on development?

Many thanks

riccardone avatar Oct 25 '20 10:10 riccardone

Trying an implementation of what @Oleg26Dev put together in his sample code into a .NET 6 Blazor Server application. Able to get it to work when a Controller is added. But, the HttpContextAccessor.GetMultiTenant() is always null. How does Blazor's HttpContextAccessor communicate to the GetMultiTenant()?

My setup is using the EFStore with RouteStrategy.

//Allows accessing HttpContext in Blazor
builder.Services.AddHttpContextAccessor();

builder.Services.AddScoped();

builder.Services.AddMultiTenant()
    .WithEFCoreStore()
    .WithRouteStrategy()
    .WithPerTenantOptions((options, tenantInfo) =>
    {
        // Since we are using the route strategy configure each tenant
        // to have a different cookie name and adjust the paths.
        options.Cookie.Path = $"/{tenantInfo.Identifier}";
        options.Cookie.Name = $"{tenantInfo.Id}_authentication";
        options.LoginPath = $"{options.Cookie.Path}{options.LoginPath}";
        options.LogoutPath = $"{options.Cookie.Path}{options.LogoutPath}";
    });

...

app.UseMultiTenant();
app.MapBlazorHub();
app.MapControllerRoute("default", "{__tenant__=}/{controller=Home}/{action=Index}");
app.MapFallbackToPage("/_Host");

Then, when I use the same ContextHelper class, the GetMultiTenantContext is null.

private readonly IHttpContextAccessor _accessor;

public ContextHelper(IHttpContextAccessor accessor)
{
     _accessor = accessor;
}

public TenantInfo GetCurrentTenant()
{
      var context = _accessor.HttpContext;
      var ti = context.GetMultiTenantContext().TenantInfo;
      return ti;
}

Am I missing something in the Progam.cs class?

jaltenbernd avatar Mar 06 '22 17:03 jaltenbernd

@jaltenbernd I dont have an answer for your main question, Andrew might pop in an answer but I wanted to let you know the source code is pretty straight forward regarding the HttpContext.

https://github.com/Finbuckle/Finbuckle.MultiTenant/blob/main/src/Finbuckle.MultiTenant.AspNetCore/Extensions/HttpContextExtensions.cs#L18

Ultimately, GetIdentifier on the strategy is called https://github.com/Finbuckle/Finbuckle.MultiTenant/blob/main/src/Finbuckle.MultiTenant.AspNetCore/Strategies/RouteStrategy.cs#L24

This might lead you down the right road.

Worst case scenario, you could clone and reference the code and actually debug and step through everything.

VictorioBerra avatar Mar 06 '22 18:03 VictorioBerra

Hello, the short answer is Blazor support isn't quite where I want it to be yet. The route strategy does not coexist well with it.

However, the base path strategy can work. Try this for your setup. A few things to note:

  1. WithBasePathStrategy(options => options.RebaseAspNetCorePathBase = true); the true option is needed for this to work
  2. UseStaticFiles must come after UseMultiTenant
  3. In your component don't inject IHttpContextAccessor but inject IMultiTenantContextAccessor<T> or your tenant info directly.
  4. If you want to have non-tenant content I recommend you create a default tenant and use it with WithStaticStrategy after WithBasePathStrategy. This will ensure a tenant always is there so you don't have to constantly check it for null and allow for a homepage or similar to work where no tenant is needed.

Hope this helps!

using BlazorServerTest.Data;
using Finbuckle.MultiTenant;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();

builder.Services.AddMultiTenant<TenantInfo>()
    .WithConfigurationStore()
    .WithBasePathStrategy(options => options.RebaseAspNetCorePathBase = true);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseMultiTenant();
app.UseStaticFiles();

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

AndrewTriesToCode avatar Mar 07 '22 01:03 AndrewTriesToCode

Did what you recommended above, but my IMultiTenantContextAccessor<TenantInfo> that I inject into the page has the MultiTenantContext as null.

jaltenbernd avatar Mar 26 '22 20:03 jaltenbernd

Hi @jaltenbernd, can you paste your configuration or link to a repo that I can look at?

AndrewTriesToCode avatar Apr 01 '22 04:04 AndrewTriesToCode

Anyone looking for a pretty good example of how to use Finbuckle with Blazor can check these out (they helped me a ton): https://fullstackhero.net/blazor-webassembly-boilerplate/general/getting-started/ https://fullstackhero.net/dotnet-webapi-boilerplate/general/getting-started/

marcmontecalvo avatar Nov 29 '22 21:11 marcmontecalvo

@marcmontecalvo How? Your two posts are just general information about Blazor. How does it help with Finbuckle?

jaltenbernd avatar Nov 29 '22 21:11 jaltenbernd

@AndrewTriesToCode

Hello, the short answer is Blazor support isn't quite where I want it to be yet. The route strategy does not coexist well with it.

Is this something that needs updated in this repo or is it a Blazor issue? I haven't dug into Blazor yet, but am about to dive head first and know I need this working haha. Do you need help with this? I can try my best.

natelaff avatar Jan 13 '23 01:01 natelaff

@natelaff glad to here from you. It's mainly a priority / time issue I think.

The routing in Blazor as described here does have an event to hook into the route changing, but it's not part of the normal request "middleware" that Finbuckle normally uses for ASP.NET Core when setting the tenant for a request. That being said there's no reason that TenantResolver and IMultiTenantContextAccessor<T> can't be used here to set the tenant--that's what I would try first.

AndrewTriesToCode avatar Jan 17 '23 04:01 AndrewTriesToCode