8

Autofac 3.0 将支持MultitenantIntegration ,其预览版现已发布。为了尝试,我创建了一个 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

1 回答 1

5

多租户支持由来已久,只是 3.0 是我们第一次为它提供 NuGet 包。:)

RequestParameterTenantIdentificationStrategy文档所述,这只是一个非常简单的示例,显示了一种可能(但不推荐)识别租户的方法。您必须自己选择如何根据运营环境来识别您的租户。它可能来自web.config当前环境中的值、环境变量或其他东西。如果您不想使用HttpContext.Current,请不要使用。您可以选择从哪里获取该信息。

(关于RPTIStrategy- 不推荐的部分是使用查询字符串或请求参数作为租户 ID 机制的注释。我HttpContext在我的生产应用程序中使用它,它工作正常。在你必须实际之前,你只能抽象出这么多触摸裸露的金属。)

没有开箱即用的方法来提供您要求的 lambda 注册语法,主要是因为租户没有通过解析过程。解决过程是:

  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();

同样,您需要再次检查我,但我很确定(或微小的变化)应该可以为您提供您想要的。

于 2012-12-24T04:57:02.170 回答