Autofac Web Api多租户未获得HTTPContext.Current

时间:2017-01-26 14:20:34

标签: c# autofac

我很难让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。似乎这个想法可能不适用于自托管服务?

1 个答案:

答案 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;
    }
}

同样,我没有试过这个,所以你可能不得不调整它,但希望它会让你开始。