6

Autofac 3.0将有一个MultitenantIntegration支持和its preview release is out现在。为了尝试一下,我创建了以下配置一个ASP.NET Web API应用程序:Autofac多租户IoC容器在ASP.NET Web API应用

public class Global : System.Web.HttpApplication { 

    protected void Application_Start(object sender, EventArgs e) { 

     var config = GlobalConfiguration.Configuration; 
     config.Routes.MapHttpRoute("Default", "api/{controller}"); 
     RegisterDependencies(config); 
    } 

    public void RegisterDependencies(HttpConfiguration config) { 

     var builder = new ContainerBuilder(); 
     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 

     // creates a logger instance per tenant 
     builder.RegisterType<LoggerService>().As<ILoggerService>().InstancePerTenant(); 

     var mtc = new MultitenantContainer(
      new RequestParameterTenantIdentificationStrategy("tenant"), 
      builder.Build()); 

     config.DependencyResolver = new AutofacWebApiDependencyResolver(mtc); 
    } 
} 

它能够完成任务,并创建一个LoggerService实例作为ILoggerService每个租户。我在这个阶段,两个问题,我是不是能解决:

  1. 我开箱即用的只是这个演示应用程序提供RequestParameterTenantIdentificationStrategy这里作为TenantIdentificationStrategy。我可以通过实施ITenantIdentificationStrategy界面来创建自定义TenantIdentificationStrategy。然而,TryIdentifyTenant方法ITenantIdentificationStrategy使您依赖于一个静态实例,如HttpContext.Current这是我不想在ASP.NET Web API环境中的东西,因为我希望我的API托管不可知论者(我知道我可以委托这项工作的托管层,但我宁愿不)。有没有另一种方式来实现这一点,我不会依赖一个静态实例?
  2. 我也有机会登记为以下租户特定实例:

    mtc.ConfigureTenant("tenant1", cb => cb.RegisterType<Foo>() 
                .As<IFoo>().InstancePerApiRequest()); 
    

    然而,我的情形之一,需要我通过构造函数的参数传递房客的名字,我很想有类似下面:

    mtc.ConfigureTenant((cb, tenantName) => cb.RegisterType<Foo>() 
                .As<IFoo>() 
                .WithParameter("tenantName", tenantName) 
                .InstancePerApiRequest()); 
    

    目前没有这样的API。还有另外一种方法可以达到这个要求吗?或者这种要求没有任何意义?

回答

4

多租户支持已经可用很长时间了,只是3.0版本是我们第一次使用NuGet软件包。 :)

如记录,RequestParameterTenantIdentificationStrategy只是一个非常简单的例子,显示了一种可能(和不推荐)的方式来确定租户。您必须自己选择如何根据运营环境来识别租户。它可能来自于web.config的值,环境变量或当前环境中的其他东西。如果你不想使用HttpContext.Current,不要。这取决于你从哪里获得信息。

(在RPTIStrategy的说明 - 未使用查询字符串或请求参数作为租户ID机制建议的一部分,我在我的生产应用程序使用HttpContext,它工作正常这里只有这么多,你可以抽象。在你不得不实际触摸裸机之前)。

没有办法提供您要求的lambda注册语法,主要是因为tenant未通过解析过程。解决过程如下:

  1. 确定租户的策略。
  2. 查找租户的配置生命周期范围。
  3. 使用标准的Autofac Resolve风格语法。

这是故意简单和类似于现有的操作。在解决的时候,属于租户的子生命周期范围是带有租户ID的标记为,但解析操作不知道租户ID ......所以lambda不起作用(并且可能赢得了因为它会改变Autofac工作方式的基础内部结构)。

来完成你在找什么,在注册时可以使用InstancePerTenant扩展的组合...

var builder = new ContainerBuilder(); 
builder.RegisterType<Foo>().As<IFoo>().InstancePerTenant(); 

...和注册ITenantIdentificationStrategy在你的容器的依赖。

builder.Register(myIdStrategy).As<ITenantIdentificationStrategy>(); 

然后让您的班级直接取ITenantIdentificationStrategy而不是租户ID。改用策略来取得租户ID。

如果您真的想获得幻想,您可以注册一个解析ID策略的键控lambda,然后获取租户ID。然后,您可以像添加参数注册一样对象,但使用键控服务。 (我要去内存现在得走了,所以你必须在这里仔细检查我的语法,但它会是这样......)

builder.Register(c => 
     { var s = c.Resolve<ITenantIdentificationStrategy>(); 
      object id; 
      s.TryIdentifyTenant(out id); 
      return id; 
     }).Keyed<object>("tenantId"); 

builder.RegisterType<Foo>() 
     .As<IFoo>() 
     .WithParameter(
     (pi, c) => pi.Name == "tenantId", 
     (pi, c) => c.ResolveKeyed<object>("tenantId")) 
     .InstancePerApiRequest(); 

再次,你要仔细检查我,但我很确定(或一个小的变化)应该工作,以获得你想要的。

+0

谢谢特拉维斯。真的很有帮助。你最后的样品真的是我正在寻找的。我应该考虑过之前:)所以,我的ITenantIdentificationStrategy需要真正的静态对象。那么对我来说没有其他选择,而不是将'TenantIdentificationStrategy'委托给具有每个请求静态上下文的宿主层。 – tugberk