Asp.net

ASP.NET Web API 應用程序中的 Autofac 多租戶 IoC 容器

  • October 1, 2014

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。是否有另一種方法來實現這個或這種要求沒有任何意義?

多租戶支持由來已久,只是 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();

同樣,您需要再次檢查我,但我很確定(或微小的變化)應該可以為您提供您想要的。

引用自:https://stackoverflow.com/questions/14013885