[英]Resolving dependencies in the ConfigureMultitenantContainer
I am trying to resolve ITenantIdentificationStrategy
in the ConfigureMultitenantContainer
but I am having An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll
.我正在尝试解决
ConfigureMultitenantContainer
中的ITenantIdentificationStrategy
但我An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll
。
I have registered the TenantResolverStrategy
in the ConfigureContainer
:我已经在
ConfigureContainer
中注册了TenantResolverStrategy
:
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterType<TenantResolverStrategy>().As<ITenantIdentificationStrategy>();
}
I want to resolve the ITenantIdentificationStrategy
in the ConfigureMultitenantContainer
:我想解决
ConfigureMultitenantContainer
中的ITenantIdentificationStrategy
:
public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
var strategy = container.Resolve<ITenantIdentificationStrategy>();
var mtc = new MultitenantContainer(strategy, container);
// mtc.ConfigureTenant("a", cb => cb.RegisterType<TenantACustom>().As<ITenantCustom>());
return mtc;
}
However it is throwing An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll
.但是它抛出
An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll
。
My ITenantIdentificationStrategy
is implemented this way:我的
ITenantIdentificationStrategy
是这样实现的:
public class TenantResolverStrategy : ITenantIdentificationStrategy
{
public TenantResolverStrategy(
IHttpContextAccessor httpContextAccessor,
IMemoryCache memoryCache,
TenantEntity tenantEntity
)
{
this.httpContextAccessor = httpContextAccessor;
this.memoryCache = memoryCache;
this.tenantEntity = tenantEntity;
}
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = null;
var context = httpContextAccessor.HttpContext;
var hostName = context?.Request?.Host.Value;
tenantEntity = GetTenant(hostName);
if (tenantEntity != null)
{
tenantId = tenantEntity.TenantCode;
}
return (tenantId != null || tenantId == (object)"");
}
}
And I register the ConfigureMultitenantContainer
in the Program.cs
as follows:我在
Program.cs
中注册了ConfigureMultitenantContainer
,如下所示:
var host = Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
I couldn't resolve other dependencies which I register in the ConfigureContainer
as well.我也无法解决我在
ConfigureContainer
中注册的其他依赖项。 Is there anything wrong with my implementation?我的实施有什么问题吗?
There are a few things that may be causing you trouble here.这里有几件事可能会给您带来麻烦。
First, I see your tenant ID strategy is not a singleton .首先,我看到您的租户 ID 策略不是 singleton 。
builder.RegisterType<TenantResolverStrategy>().As<ITenantIdentificationStrategy>();
That's trouble, because every single resolution from the tenant ID strategy is going to go through a single instance of the tenant ID strategy.这很麻烦,因为租户 ID 策略的每个解析都通过租户 ID 策略的单个实例转到 go。 It's going to be cached.
它将被缓存。 However, resolving the strategy is going to resolve different values and be misleading.
但是,解决策略将解决不同的价值观并具有误导性。
Consider:考虑:
var strategy = container.Resolve<ITenantIdentificationStrategy>();
// The multitenant container is CACHING THIS.
var mtc = new MultitenantContainer(container, strategy);
// Now, later on you maybe resolve another instance of the strategy:
var anotherInstance = mtc.Resolve<ITenantIdentificationStrategy>();
// Or from the root:
var thirdInstance = container.Resolve<ITenantIdentificationStrategy>();
// OH NO! strategy != anotherInstance != thirdInstance
// These ARE NOT THE SAME INSTANCE. Tenant determination may CHANGE
// based on which one of these is used.
Make your tenant ID strategy a singleton.将您的租户 ID 策略设为 singleton。
Next, since the strategy is cached in the multitenant container, you can't maintain state .接下来,由于策略缓存在多租户容器中,因此您无法维护 state 。 This is super important because you will run into tons of threading issues.
这非常重要,因为您会遇到大量线程问题。
public class TenantResolverStrategy : ITenantIdentificationStrategy
{
public TenantResolverStrategy(
IHttpContextAccessor httpContextAccessor,
IMemoryCache memoryCache,
TenantEntity tenantEntity
)
{
this.httpContextAccessor = httpContextAccessor;
this.memoryCache = memoryCache;
// PROBLEM! Where is TenantEntity coming from?
this.tenantEntity = tenantEntity;
}
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = null;
var context = httpContextAccessor.HttpContext;
var hostName = context?.Request?.Host.Value;
// PROBLEM: Incorrectly storing state in the strategy
// when this is used across threads. (There's also no
// explanation of what's in GetTenant, so it's hard to
// help with that.)
tenantEntity = GetTenant(hostName);
if (tenantEntity != null)
{
tenantId = tenantEntity.TenantCode;
}
return (tenantId != null || tenantId == (object)"");
}
}
You can maintain a cache, but don't maintain state.您可以维护缓存,但不要维护 state。 For example, maybe you need a
Dictionary<string, object>
to cache hostname to tenant ID mappings, and that's fine (as long as you do locking around that, or use a thread-safe dictionary).例如,也许您需要一个
Dictionary<string, object>
来缓存主机名到租户 ID 的映射,这很好(只要您锁定它,或者使用线程安全字典)。 But you have a single object that can be overwritten across threads and that's bad news.但是你有一个可以跨线程覆盖的object ,这是个坏消息。
Next, I see your tenant ID strategy takes dependencies.接下来,我看到您的租户 ID 策略需要依赖项。 Generally, I'd avoid this and construct it directly.
一般来说,我会避免这种情况并直接构建它。 I know that's not great for some folks, but there is a tendency to "over-DI" things that shouldn't be involved in DI.
我知道这对某些人来说不是很好,但是有一种趋势是“过度 DI”不应该涉及 DI 的事情。 Manually constructing base objects like a
ContainerBuilder
or your tenant ID strategy ensures you're only looking at things that you can control (and it avoids these exceptions like you've seen).手动构建像
ContainerBuilder
或租户 ID 策略这样的基础对象可确保您只查看您可以控制的内容(并且它可以避免这些异常,就像您所看到的那样)。
You should be able to manually resolve any dependencies that go into the tenant ID strategy.您应该能够手动将 go 的任何依赖项解析为租户 ID 策略。 For example, this should work:
例如,这应该有效:
public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
// These are the dependencies of the strategy. You don't NEED TO DO THIS
// but if you put these in here, it SHOULD NOT BLOW UP. If it does, you know
// where to start tracing things down.
var accessor = container.Resolve<IHttpContextAccessor>();
var cache = container.Resolve<IMemoryCache>();
var entity = container.Resolve<TenantEntity>();
// Here's the strategy - again, make sure it's a SINGLETON!
var strategy = container.Resolve<ITenantIdentificationStrategy>();
var mtc = new MultitenantContainer(strategy, container);
// mtc.ConfigureTenant("a", cb => cb.RegisterType<TenantACustom>().As<ITenantCustom>());
return mtc;
}
That said, I recognize that things like database connections may need to be injected, in which case, again, be sure things are marked as singletons .也就是说,我认识到可能需要注入诸如数据库连接之类的东西,在这种情况下,再次确保将事物标记为singletons 。 Your multitenant container tenant ID strategy will live for the lifetime of the application.
您的多租户容器租户 ID 策略将在应用程序的整个生命周期内有效。 Plus, nothing that depends on a tenant ID strategy (like the multitenant container) should be tenant-specific or request-based because... you can't determine the tenant without a valid tenant ID strategy.
此外,任何依赖于租户 ID 策略(如多租户容器)的内容都不应是特定于租户或基于请求的,因为......如果没有有效的租户 ID 策略,您将无法确定租户。 Circular dependency!
循环依赖!
So, boiling it all down:所以,把它全部煮沸:
TenantEntity
).TenantEntity
)。TenantEntity
instance variable; make it a method-level local variable if you need to).TenantEntity
实例变量;如果需要,将其设为方法级别的局部变量) .IHttpContextAccessor
(or IMemoryCache
, or whatever) that needs to be registered.IHttpContextAccessor
(或IMemoryCache
或其他)。 Try resolving those dependencies directly if you run into trouble;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.