我正在升级使用Autofac.Multitenant框架的Multitenant dotnet核心解决方案。我没有很多运气让租约解决方案正常工作。我在这里创建了一个简单的问题演示:https://github.com/SaltyDH/AutofacMultitenancy1
此repo演示了在归属控制器中解析的InstancePerTenant
作用域依赖TestMultitenancyContext
。由于使用IHttpContextAccessor的问题,我使用自定义RequestMiddleware
类来捕获当前的HttpContext对象,以便我可以在MultitenantIdentificationStrategy
中的当前HttpContext请求对象上执行逻辑。
最后,TestFixture
提供了一个简单的xUnit测试,至少在我的机器上为两个租户返回“tenant1”。
我在这里错过了什么,或者目前还没有工作?
答案 0 :(得分:0)
我有一个替代解决方案,与我在Autofac DI扩展程序pending PR上完成的工作相关。那里的解决方案不能完全使用,因为它取决于(正确的)内部类。它可以通过提供在这些类中重现功能的垫片来进行调整。由于它们很紧凑,因此不需要添加大量代码。在功能修复之前,这是我正在使用的解决方案。
该解决方案的另一个方面是避开自定义中间件,而是使ITenantIdentificationStrategy
服务可以采取任何必要的依赖来完成它所需的工作。
" DI"问题的一面是Autofac DI扩展使用分辨率来提供IServiceProvider
和IServiceScopeFactory
实现。这是可能的,因为在引擎盖下这些是IComponentContext
和ILifetimeScope
(它们本身是同一事物的不同接口)。在大多数情况下,这样可以正常工作,但ASP.NET Core会在应用程序周期的早期解析单个IServiceScopeFactory
。在多租户方案中,此解决方案将为所请求的第一个租户或"默认"返回ILifetimeScope
。租户,这将是应用程序生命周期的根范围(就MS DI而言)。 (有关进一步的讨论,请参阅PR。)
下面的类实现了一个替代行为:它不是解析DI接口,而是直接从new
构建(IContainer
s-up)最初请求的接口。最初的IServiceScopeFactory
直接基于IContainer
,进一步的范围请求将正确解析。
public class ContainerServiceProvider : IServiceProvider, ISupportRequiredService
{
private readonly IContainer container;
public ContainerServiceProvider(IContainer container)
{
this.container = container;
}
public object GetRequiredService(Type serviceType)
{
if (TryGetContainer(serviceType, out object containerSvc)) return containerSvc;
else return container.Resolve(serviceType);
}
public object GetService(Type serviceType)
{
if (TryGetContainer(serviceType, out object containerSvc)) return containerSvc;
else return container.ResolveOptional(serviceType);
}
bool TryGetContainer(Type serviceType, out object containerSvc)
{
if (serviceType == typeof(IServiceProvider)) { containerSvc = this; return true; }
if (serviceType == typeof(IServiceScopeFactory)) { containerSvc = new ContainerServiceScopeFactory(container); return true; }
else { containerSvc = null; return false; }
}
}
// uses IContainer, but could use copy of AutofacServiceScopeFactory
internal class ContainerServiceScopeFactory : IServiceScopeFactory
{
private IContainer container;
public ContainerServiceScopeFactory(IContainer container)
{
this.container = container;
}
public IServiceScope CreateScope()
{
return new BecauseAutofacsIsInternalServiceScope(container.BeginLifetimeScope());
}
}
// direct copy of AutofacServiceScope
internal class BecauseAutofacsIsInternalServiceScope : IServiceScope
{
private readonly ILifetimeScope _lifetimeScope;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceScope"/> class.
/// </summary>
/// <param name="lifetimeScope">
/// The lifetime scope from which services should be resolved for this service scope.
/// </param>
public BecauseAutofacsIsInternalServiceScope(ILifetimeScope lifetimeScope)
{
this._lifetimeScope = lifetimeScope;
this.ServiceProvider = this._lifetimeScope.Resolve<IServiceProvider>();
}
/// <summary>
/// Gets an <see cref="IServiceProvider" /> corresponding to this service scope.
/// </summary>
/// <value>
/// An <see cref="IServiceProvider" /> that can be used to resolve dependencies from the scope.
/// </value>
public IServiceProvider ServiceProvider { get; }
/// <summary>
/// Disposes of the lifetime scope and resolved disposable services.
/// </summary>
public void Dispose()
{
this._lifetimeScope.Dispose();
}
}
至于将识别策略作为服务,我会像你这样重写你的实现:
public class MultitenantIdentificationStrategy : ITenantIdentificationStrategy
{
public const string DefaultTenantId = null;
private readonly IHttpContextAccessor contextaccessor;
public MultitenantTenantIdentificationStrategy(IHttpContextAccessor contextaccessor)
{
this.contextaccessor = contextaccessor;
}
public bool TryIdentifyTenant(out object tenantId)
{
var context = contextaccessor.HttpContext;
// after this is unchanged
.
.
}
.
.
}
这显示了这些最后几个部分如何注册并提供给ASP.NET的MS DI的片段。
. . .
builder.RegisterType<MultitenantIdentificationStrategy>().AsImplementedInterfaces(); // tenant identification
// register do Autofac DI integration
builder.Populate(services);
var underlyingcontainer = builder.Build();
ApplicationContainer = new MultitenantContainer(underlyingcontainer.Resolve<ITenantIdentificationStrategy>(), underlyingContainer);
return new ContainerServiceProvider(ApplicationContainer);
如果您发现此解决方案可行,请赞同DI PR 10 - 或PR 11,如果在审核后您认为这是更好/更优雅的解决方案。要么省去必须添加&#34; shim&#34;上面的代码。