我試圖重構一個現有的解決方案(沒有寫它)使用DI和Autofac,並且遇到了一些問題。所討論的解決方案支持許多SQL數據庫類型(MSSQL,MySQL,PostgreSQL,可能更多),並且用戶可以在應用程序中連接各種數據庫(即它們可能同時具有MSSQL和PostgreSQL DB連接)。當數據庫連接到應用程序時,類型存儲在枚舉中。當採取動作上有問題的DB它目前使用下列靜態工廠返回一個數據層:使用Autofac創建一個可以返回不同SQL引擎的工廠
public static class DatabaseFactoryController
{
public static IDatalayer GetDatalayer(ConnType databaseType)
{
switch (databaseType)
{
case ConnType.Mssql:
return new MssqlModel());
case ConnType.Postgre:
return new PostgreModel());
case ConnType.MySql:
return new MysqlModel());
default:
throw new ArgumentOutOfRangeException(nameof(databaseType));
}
}
}
現在的問題是,在代碼中的其他控制器需要有注射數據庫用戶的正確數據層當前正在訪問像例如:
public class SizeController : IDataController
{
private readonly IDatalayer _datalayer;
public SizeController(IDatalayer datalayer)
{
_datalayer = datalayer;
}
public Response<SizeInfo> GetData(IRequest request)
{
<actions taken here using datalayer>
}
}
但我怎樣才能線了Autofac動態地注入右數據層中的控制器,用於選擇用於任何給定的呼叫(控制器的實例)的DB而無需進入的ServiceLocator。我非常肯定它必須是可能的,但我對Autofac很新,所以也許這就是爲什麼我似乎無法使其基於文檔工作。我試過以下這一點:https://benedict-chan.github.io/blog/2014/08/13/resolving-implementations-at-runtime-in-autofac/
builder.RegisterType<MssqlDatalayer>()
.As<IDatalayer>().Keyed<IDatalayer>(ConnType.Mssql);
builder.RegisterType<PostgreDatalayer>()
.As<IDatalayer>().Keyed<IDatalayer>(ConnType.Postgre);
builder.Register<Func<ConnType, IDatalayer>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (roleName) =>
{
var dataService = componentContext.ResolveKeyed<IDatalayer>(roleName);
return dataService;
};
});
builder.RegisterType<SizeController>().As<IDataController>()
但在執行我不看我怎麼挑注入在運行時的構造函數的實現。也許我錯過了一些明顯的東西,或者我需要從根本上重構代碼。任何輸入都會被重視,因爲我一直在這個問題上停留了一段時間。
'他們可能同時具有MSSQL和PostgreSQL數據庫connected'在這種情況下,應IDatalayer它選擇呢? MS的一個還是Postgres的? – mjwills
與請求的ConnType一致,但我想我現在看到下面給出了Aleksey的答案。我必須在運行時將ConnType作爲參數傳入,然後才能選擇正確的實現。 –