05 | 依賴注入:良好架構的起點
除了使用泛型的方式注冊服務之外,還有其他的方式
添加一個 OrderService
public interface IOrderService
{
}
public class OrderService : IOrderService
{
}
public class OrderServiceEx : IOrderService
{
}
在 Startup 中注冊服務
public void ConfigureServices(IServiceCollection services)
{
#region 注冊服務不同生命周期的服務
// 將單例的服務注冊為單例的模式
services.AddSingleton<IMySingletonService, MySingletonService>();
// Scoped 的服務注冊為 Scoped 的生命周期
services.AddScoped<IMyScopedService, MyScopedService>();
// 瞬時的服務注冊為瞬時的生命周期
services.AddTransient<IMyTransientService, MyTransientService>();
#endregion
#region 花式注冊
services.AddSingleton<IOrderService>(new OrderService()); //直接注入實例
//// 通過工廠模式
//services.AddSingleton<IOrderService>(serviceProvider =>
//{
// return new OrderServiceEx();
//});
//services.AddScoped<IOrderService>(serviceProvider =>
//{
// // 可以使用 IServiceProvider 入參,也就意味着可以從容器里面獲取多個對象,進行組裝,得到最終的實現實例
// // 也就是可以把工廠類設計的比較復雜,比如說實現類依賴了容器里面的另外一個類,或者用另一個類來包裝原有的實現
// //serviceProvider.GetService<>()
// return new OrderServiceEx();
//});
#endregion
#region 嘗試注冊(如果服務已經注冊過,則不再注冊)
services.TryAddSingleton<IOrderService, OrderServiceEx>();
#endregion
services.AddControllers();
}
在服務端 WeatherForecastController 定義另外一個接口
// IEnumerable<IOrderService>:獲取曾經注冊過的所有 IOrderService
public int GetServiceList([FromServices]IEnumerable<IOrderService> services)
{
foreach (var item in services)
{
Console.WriteLine($"獲取到服務實例:{item.ToString()}:{item.GetHashCode()}");
}
return 1;
}
調整一下程序的啟動頁面,Properties 下的 launchSetting.json 的這一行代碼
"launchUrl": "weatherforecast/getservicelist",
啟動程序,輸出如下:
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:25560520
只有一個實例,說明 TryAddSingleton 沒有生效
接着,注冊兩個服務
services.AddSingleton<IOrderService>(new OrderService());
services.AddSingleton<IOrderService, OrderServiceEx>();
啟動程序,輸出如下:
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:16991442
獲取到服務實例:DependencyInjectionDemo.Services.OrderServiceEx:25560520
結果獲取到了兩個實例
接下來,了解一下 TryAddEnumerable 與 TryAddSingleton 的區別
#region 嘗試注冊(如果服務已經注冊過,則不再注冊)
services.TryAddSingleton<IOrderService, OrderServiceEx>();// 接口類型重復,則不注冊
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderService>());// 相同類型的接口,實現類相同,則不注冊
#endregion
注冊服務
services.AddSingleton<IOrderService>(new OrderService());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderService>());
啟動程序,輸出如下:
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:53046438
因為已經注冊過 OrderService,所以第二句代碼不生效
以不同的實現注冊服務
services.AddSingleton<IOrderService>(new OrderService());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>());
啟動程序,輸出如下:
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:24219861
獲取到服務實例:DependencyInjectionDemo.Services.OrderServiceEx:38855053
這樣就可以獲取到兩個服務實例
刷新瀏覽器,再執行一遍
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:24219861
獲取到服務實例:DependencyInjectionDemo.Services.OrderServiceEx:38855053
獲取到服務實例:DependencyInjectionDemo.Services.OrderService:24219861
獲取到服務實例:DependencyInjectionDemo.Services.OrderServiceEx:38855053
因為注冊的是單例,所以兩次請求獲取到的實例都是相同的
這樣做的好處是:一方面避免一個服務重復注冊,也可以控制一個服務需要注冊不同的實現
本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。
如有任何疑問,請與我聯系 (MingsonZheng@outlook.com) 。