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

Suggestion for a possible enhancement to entity framework documentation page #890

Open hurcane opened 6 days ago

hurcane commented 6 days ago

I'm new to Finbuckle, and also relatively new to ASP.NET Core and dependency injection, so this suggestion may not be helpful. Please let me know!

I am working on implementing multitenant behavior in a web site that uses separate databases for tenant isolation. In the current docs, it is suggested to use the following constructor on the sample EF context class, MyAppDbContext.

public MyAppDbContext(IMultiTenantContextAccessor<AppTenantInfo> multiTenantContextAccessor)
{
   // get the current tenant info at the time of construction
   TenantInfo = multiTenantContextAccessor.tenantInfo;
} 

When I tried the sample approach, the dependency injection framework complained about ambiguous constructors. It didn't like that I had this constructor on my class.

public MyAppDbContext(DbContextOptions<MyAppDbContext> options)
    : base(options)
{ }

As I understand EF Core, this is a pretty standard constructor. In my project, the EF Context class is used in multiple projects, and these other projects are using the DbContextOptions constructor.

The solution I found for this situation was to handle the multi-tenant configuration for the connection string while building the services. Between the builder.Services.AddMultiTenant<> line and the app.UseMultiTenant() line, the DbContext is configured like this:

builder.Services.AddDbContext<MyAppDbContext>((serviceProvider, dbContextBuilder)=>
{
    var tenantAccessor = serviceProvider.GetRequiredService<IMultiTenantContextAccessor<AppTenantInfo>>();
    dbContextBuilder.UseSqlServer(
        tenantAccessor.MultiTenantContext.TenantInfo.ConnectionString);
});

I wonder if this is even a good way of handling this situation, given my newbie status to these concepts. If it is a good solution, would this information be useful to be added to the documentation as an alternative to using the IMultiTenantContextAccessor constructor and the OnConfiguring method?

AndrewTriesToCode commented 5 days ago

I like this idea. Please feel free to submit a PR with the change or I can it with the .net 9 release.

Another option is to use:

public MyAppDbContext(IMultiTenantContextAccessor<AppTenantInfo> multiTenantContentAccessor, DbContextOptions<MyAppDbContext> options)
    : base(multiTenantContentAccessor, options)
{ }