我很难让Autofac.Extras.Multitenancy包在两个接口实现之间进行选择。
我尝试根据租户ID连接到不同的数据库,但我从Autofac的示例中获取的ITenantIdentificationStrategy
并未设置HttpContext.Current
,所以我无法从HTTP调用中获取任何内容以做出决定。我有两个这样的配置。
var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
mtc.ConfigureTenant(Guid.Parse("00000000-0000-0000-0000-000000000001"), b => b.RegisterInstance<DatabaseConnection>(connectionOne).As<IDatabaseConnection>().SingleInstance());
mtc.ConfigureTenant(Guid.Parse("00000000-0000-0000-0000-000000000002"), b => b.RegisterInstance<DatabaseConnection>(connectionTwo).As<IDatabaseConnection>().SingleInstance());
var resolver = new AutofacWebApiDependencyResolver(mtc);
config.DependencyResolver = resolver;
appBuilder.UseWebApi(config);
所以我实例化了两个数据库连接,我希望这些实例分别用于每个租户
我的租户ID非常简单
public class RequestParameterStrategy : ITenantIdentificationStrategy
{
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = null;
try
{
var context = HttpContext.Current;
if (context != null && context.Request != null)
{
tenantId = HttpContext.Current.Request.RequestContext.RouteData.Values["tenantId"];
}
}
catch (HttpException)
{
// Happens at app startup in IIS 7.0
}
return tenantId != null;
}
}
我添加了一个简单的控制器来测试它应该在ASP.NET管道中。
public IHttpActionResult Get(IMongoDBAdapter adapter, string memberId= null) {
return Ok()
}
这是Autofac网站上的例子。但是HttpContext.Current总是为null并且未设置租户ID,然后它抱怨我的控制器没有得到DatabaseConnection
修改 我认为我的问题可能是该项目未在IIS中托管。它是一个自托管的Windows服务,甚至在控制器中HttpContext.Current为null。似乎这个想法可能不适用于自托管服务?
答案 0 :(得分:2)
你是对的 - you won't get HttpContext
in a self hosted environment
您可以try writing a custom DelegatingHandler
位于自托管请求管道中的第一位,并以与ASP.NET Core has an HttpContextAccessor
也就是说,您的DelegatingHandler
必须......
CallContext.LogicalSetData
然后,您的租户ID策略将使用CallContext.LogicalGetData
读取该值。
了解ASP.NET Core gets/sets HttpContext.Current
doing a very, very similar thing 的方式,因为ASP.NET Core也不支持HttpContext.Current
。
实际上这可能是一些棘手的代码,所以我会在这里添加一个非常非常粗略的样本,但是不要只是复制/粘贴它并假设它将是100%完美即可。我没有对它进行大量测试,我只想给你一个想法。
以下是处理程序的外观:
public class TenantIdentityHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var id = request.Headers.GetValues("X-Tenant-ID").FirstOrDefault();
CallContext.LogicalSetData("TenantIdentification" + AppDomain.CurrentDomain.Id, new ObjectHandle(id));
return await base.SendAsync(request, cancellationToken);
}
}
以下是您的ID策略的样子:
public class CallContextStrategy : ITenantIdentificationStrategy
{
public bool TryIdentifyTenant(out object tenantId)
{
var handle = CallContext.LogicalGetData("TenantIdentification" + AppDomain.CurrentDomain.Id) as ObjectHandle;
var tenantId = handle?.Unwrap() as string;
return tenantId != null;
}
}
同样,我没有试过这个,所以你可能不得不调整它,但希望它会让你开始。