sim*_*Vin 3 c# autofac asp.net-core
我正在构建一个带有多个数据库的多租户 asp.net core 3.1 应用程序(每个租户一个,一个主数据库)。我正在使用 Autofac 为我的服务提供单租户终身支持(现在我不需要租户覆盖,我只需要自定义 SinglePerTenant 生命周期)我正在使用
我的租户识别策略涉及对主数据库的 db 调用。
正如 autofac 的文档中所写,识别策略不应该调用数据库,因为它在每个依赖项解析中都会被调用。然后我使用了另一种租户识别解决方案(Finbuckle.MultiTenant)。
使用 Finbukle 在请求到达时调用他的识别策略(每个 htp 请求一次),我将 db 调用放在他的识别策略中(为了优化我可以缓存结果,并每天刷新一次查询)并设置一个租户信息对象在 HttpContext 中。
然后在 AutoFac 识别策略中,我尝试读取 FinBuckle 设置的对象,但这是不可能的,因为 Autofac 识别策略在 FinBuckle 之前调用,并且所需的属性为空。
我的 Program.cs 是:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Run Code Online (Sandbox Code Playgroud)
启动.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMultiTenant().WithStrategy<TestStategy>(ServiceLifetime.Singleton).WithStore<CustomTestStore>(ServiceLifetime.Singleton); //enable the multitenant support from finbukle
services.AddControllers();
services.AddAutofacMultitenantRequestServices();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseMultiTenant() //finbukle
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterType<TestDiA>().As<ITestDI>().InstancePerTenant();
}
public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
// This is the MULTITENANT PART. Set up your tenant-specific stuff here.
var strategy = new MyAutofacTenantIdentificationStrategy(container.Resolve<IHttpContextAccessor>());
var mtc = new MultitenantContainer(strategy, container);
return mtc;
}
}
Run Code Online (Sandbox Code Playgroud)
Autofac租户识别策略:
public class MyAutofacTenantIdentificationStrategy : ITenantIdentificationStrategy
{
private readonly IHttpContextAccessor httpContextAccessor;
public MyAutofacTenantIdentificationStrategy(
IHttpContextAccessor httpContextAccessor
)
{
this.httpContextAccessor = httpContextAccessor;
}
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = null;
var context = httpContextAccessor.HttpContext;
if (context == null)
return false;
var identifier = context.getTenatInfo()?.Identifier ?? null; //getTenantInfo is a method that extract the tenant info object setted by finbukle
tenantId = identifier;
return (tenantId != null || tenantId == (object)"");
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 Autofac.AspNetCore.Multitenant 3.0.0、Autofac.Extensions.DependencyInjection 6.0.0 和 FinBuckle.MultiTenant 5.0.4
我在这方面真的很新,所以如果我问一个微不足道的问题,我深表歉意。有没有办法用这种方法解决问题?
或者我的问题有替代策略吗?
目前我不相信 Finbuckle 和 Autofac.Multitenant 是兼容的。
Autofac 对 ASP.NET Core 的多租户支持依赖于在中间件管道中运行的第一件事,因此它可以设置HttpContext.RequestServices
为基于租户范围。当然,作为其中的一部分,租户识别策略将运行。
但是,Finbuckle 假设每个租户都共享一个容器,就像默认的 ASP.NET Core 功能一样。Finbuckle 中间件尝试使用HttpContext.RequestServices
基于注册策略来识别租户。
您可以看到这引发的鸡/蛋问题 - 请求服务应该基于租户生命周期范围,但租户识别策略需要从请求服务中解决问题。
但是,让我们暂时忽略它,因为问题是如何避免每次解析时都调用数据库进行识别。
如果您深入研究 Finbuckle 代码,中间件会将租户信息设置HttpContext.Items
为中间件运行的一部分。稍后,当您检索租户信息时,它会从 检索HttpContext.Items
,而不是通过数据库重新解析。数据库调用仅执行一次,即第一次运行租户 ID。
那应该没问题。根据您计划支持的租户数量以及它们更改的频率,可能值得添加某种内存缓存层,您可以使用它来存储租户 ID 数据(无论存储在数据库中的任何内容都可以帮助您识别该租户)所以你可以在访问数据库之前先尝试内存存储。也许它会定期使那里的数据过期,或者它可能是固定大小或其他什么......缓存策略完全依赖于应用程序,我无法推荐相关细节。重点是,这是减轻数据库调用的一种方法。
但是回到鸡/蛋问题,我看不出有什么简单的方法可以解决这个问题。
如果是我,我必须得到这个工作,我可能会跳过调用IApplicationBuilder.UseMultiTenant()
扩展,然后创建我自己的中间件版本,其中代替使用HttpContext.RequestServices
,以获得租户ID策略,将采取多租户容器权在构造函数就像 Autofac 多租户中间件一样,并且会直接使用应用程序级容器来解决这些策略。当然,这必须在 Autofac 多租户请求服务中间件之前运行,并且强制中间件顺序有点痛苦。最后,由于在HttpContext.Items
中间件运行后最终会获得租户标识,因此您的 AutofacITenantIdentificationStrategy
可以简单地查看那里获取数据,而根本不调用数据库。
然而...
非常重要的免责声明
我的实际建议是……嗯,放慢一点。正如您所提到的,您是这个领域的新手,而且您将在这里遇到的东西似乎很深。如果您还没有,我建议您深入研究 GitHub 上的实际 Finbuckle 代码。它看起来并不多,它可以让您了解正在发生的事情。我建议尝试创建一个仅包含 Autofac 多租户的多租户应用程序,而一个只包含芬扣。看看你是否真的需要两者。也许只有一个是有意义的。例如,Finbuckle 似乎已经有数据存储的多租户;这也是许多人使用 Autofac 多租户的目的 - 为每个租户注册不同的数据库上下文。也许只使用其中一种产品就足够了,这可以解决整个问题。
归档时间: |
|
查看次数: |
798 次 |
最近记录: |