ASP.NET Web API 應用程序中的 Autofac 多租戶 IoC 容器
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在這個階段我有兩個問題我無法解決:
- 我在
RequestParameterTenantIdentificationStrategy這裡提供的開箱即用的 TenantIdentificationStrategy 僅用於此展示應用程序。我可以通過實現ITenantIdentificationStrategy介面來創建我的自定義 TenantIdentificationStrategy。但是,TryIdentifyTenant方法ITenantIdentificationStrategy使您依賴於靜態實例,例如HttpContext.Current在 ASP.NET Web API 環境中我不想要的東西,因為我希望我的 API 託管不可知論(我知道我可以將這項工作委託給託管層,但我不想這樣做)。是否有另一種方法可以不依賴靜態實例來實現這一點?- 我還有機會註冊租戶特定實例,如下所示:
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 註冊語法,主要是因為租戶沒有通過解析過程。解決過程是:
- 使用策略辨識租戶。
- 查找租戶配置的生命週期範圍。
- 使用標準 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();同樣,您需要再次檢查我,但我很確定(或微小的變化)應該可以為您提供您想要的。