系列目錄html
按部就班學.Net Core Web Api開發系列目錄git
本系列涉及到的源碼下載地址:https://github.com/seabluescn/Blog_WebApigithub
1、概述mvc
本篇介紹如何採用依賴注入的方式建立和使用對象,主要從應用層面進行描述,不涉及具體的內部原理。app
2、演練ide
假設要作一個日誌服務的類,它實如今控制檯打印出帶時間信息的日誌信息。函數
首先定義該服務的接口與實現類。ui
public interface ILogService { void LogInfomation(string info); } public class MyLogService : ILogService { void ILogService.LogInfomation(string info) { Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}"); } }
註冊該服務this
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddCors(); services.AddSingleton<ILogService, MyLogService>(); }
註冊成功,咱們在Controller中使用該服務:spa
public class ArticleController : Controller {
private readonly ILogService _myLog; public ArticleController(ILogService myLog) { _myLog = myLog; } [HttpGet("logger")] public void TestLogger(string logger) { _myLog.LogInfomation("hahaha"); return; } }
簡單分析一下:
一、首先經過services.AddSingleton方法向依賴注入容器登記註冊MyLogService;
二、在構建Controller時,根據其構造函數類型遍歷其輸入參數,在依賴注入容器中找到該對象並做爲實參傳遞給構造方法。
3、生命週期問題
註冊一個服務,根據生命週期須要的不一樣,有下面三種方式:
services.AddSingleton<ILogService, MyLogService>(); services.AddScoped<ILogService, MyLogService>(); ervices.AddTransient<ILogService, MyLogService>();
三種註冊方式分別對應三種生命週期
1)Singleton:單例服務,從當前服務容器中獲取這個類型的實例永遠是同一個實例;
2)Scoped:每一個做用域生成周期內建立一個實例;
3)Transient:每一次請求服務都建立一個新實例;
對咱們的日誌進行改造,讓其在構建時生成一個ID,經過觀察其guid變化能夠理解這三種生命週期的區別。
public class MyLogService : ILogService { public Guid _guid; public MyLogService() { _guid = Guid.NewGuid(); } void ILogService.LogInfomation(string info) { Console.WriteLine($" ==> MyLogService : My Guid is :{_guid}"); Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}"); } }
4、經過擴展方法註冊服務
經過對IServiceCollection增長擴展方法來註冊服務
public static class MyLogServiceCollectionExtensions { public static void AddMyLog(this IServiceCollection services) { services.AddSingleton<ILogService, MyLogService>(); } }
這樣,使用者的註冊代碼能夠修改成:
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddCors();
services.AddMyLog();
}
可見AddMvc、AddCors等也是向容器注入服務。
public static IMvcBuilder AddMvc(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException("services"); } IMvcCoreBuilder mvcCoreBuilder = MvcCoreServiceCollectionExtensions.AddMvcCore(services); MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(mvcCoreBuilder); MvcCoreMvcCoreBuilderExtensions.AddAuthorization(mvcCoreBuilder); MvcServiceCollectionExtensions.AddDefaultFrameworkParts(mvcCoreBuilder.PartManager); MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(mvcCoreBuilder); MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(mvcCoreBuilder); MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(mvcCoreBuilder); MvcRazorPagesMvcCoreBuilderExtensions.AddRazorPages(mvcCoreBuilder); TagHelperServicesExtensions.AddCacheTagHelper(mvcCoreBuilder); MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(mvcCoreBuilder); MvcJsonMvcCoreBuilderExtensions.AddJsonFormatters(mvcCoreBuilder); MvcCorsMvcCoreBuilderExtensions.AddCors(mvcCoreBuilder); return new MvcBuilder(mvcCoreBuilder.Services, mvcCoreBuilder.PartManager); }
5、幾個問題
一、若是屢次註冊會怎樣
能夠屢次註冊同一種生命週期的類,以下是能夠的:
services.AddSingleton<ILogService, MyLogService>(); services.AddSingleton<ILogService, MyLogService>(); services.AddSingleton<ILogService, MyLogService>();
但下面這個代碼不行:
services.AddSingleton<ILogService, MyLogService>();
services.AddScoped<ILogService, MyLogService>();
二、如何獲取已經註冊的服務列表
經過ServicesProvider能夠獲取服務列表
services.AddMyLog(); services.AddMyLog(); services.AddMyLog(); var provider = services.BuildServiceProvider(); var servicesList = provider.GetServices< ILogService >(); foreach (var service in servicesList) { Console.WriteLine("service:" + service.ToString()); }
以上代碼輸出3條記錄。
但下面的代碼只輸出一條記錄:
services.AddCors(); services.AddCors(); services.AddCors(); var provider = services.BuildServiceProvider(); var servicesList = provider.GetServices<ICorsService>(); foreach (var service in servicesList) { Console.WriteLine("service:" + service.ToString()); }
具體緣由看一下源碼就清楚了:
public static IServiceCollection AddCors(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException("services"); } services.TryAdd(ServiceDescriptor.Transient<ICorsService, CorsService>()); return services; } public static void TryAdd(this IServiceCollection collection, ServiceDescriptor descriptor) { if (!collection.Any((ServiceDescriptor d) => d.ServiceType == descriptor.ServiceType)) { collection.Add(descriptor); } }
因此咱們應該按照這個方法修改咱們的AddMyLog方法。