ASP.NET Core技术研究-探秘依赖注入框架
ASP.NET Core在底層內置了一個依賴注入框架,通過依賴注入的方式注冊服務、提供服務。依賴注入不僅服務于ASP.NET Core自身,同時也是應用程序的服務提供者。
毫不夸張的說,ASP.NET Core通過依賴注入實現了各種服務對象的注冊和創建,同時也實現了面向抽象的編程模式和編程體驗,提升了應用程序的擴展性。
今天,我們普及一下ASP.NET Core中依賴注入的一些基本知識。
一、服務的注冊
? ?我們通過創建一個ASP.NET Core的項目,可以發現在Startup.cs 類中,有一個方法ConfigureServices,這個方法的注釋是這樣的:
? ? ?This method gets called by the runtime. Use this method to add services to the container.
? ?
? 在ConfigureServices方法中我們可以將通過ASP.NET Core內置的依賴注入框架實現服務的的注冊。
? 這個方法有個參數:IServiceCollection,見名知意,服務集合。
? ASP.NET Core內置的依賴注入框架將服務注冊信息存儲到一個實現了IServiceCollection接口的對象中。默認情況下這個接口的實現類是ServiceCollection,以下是這個類的說明:
??https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=dotnet-plat-ext-3.1
? 通過這個接口和類實現,我們可以發現,注冊服務其實就是將一個服務的ServiceDescriptor對象添加到ServiceCollection集合中。
? 例如:
public void ConfigureServices(IServiceCollection services) {services.Add(new ServiceDescriptor(typeof(IUserRepository), new UserRepository()));services.AddControllers(); }ServiceDescriptor可以理解為對某個服務注冊項的描述。ASP.NET Core的依賴注入容器IServiceProvider通過ServiceDescriptor的信息,動態創建服務的實例Instance.
? ?我們看一下這個ServiceDescriptor類:
? ?
? ?有幾個關鍵的屬性:
? ? ?1. ServiceType:服務的類型,例如服務接口的類型信息
? ? ?2. ImplementationType:服務的實現類型,例如服務接口實現類的類型信息
? ? ?3. ImplementationInstance:實現服務的實例,一般是服務單例模式場景下使用。https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor.-ctor?view=dotnet-plat-ext-3.1#Microsoft_Extensions_DependencyInjection_ServiceDescriptor__ctor_System_Type_System_Object_
? ? 4. Lifetime:服務生命周期:Scoped(同一個請求中同一個IServiceProvider提供的對象是同一個)、Singleton(單例)、Transient(每次從服務容器進行請求時創建)
? ? 5.?ImplementationFactory 服務實例創建工廠,自定義的IServiceProvider服務提供容器
? 服務注冊提供了一系列重載的方法,大家可以根據需要進行選擇:
??
? ? ?服務注冊的過程中,涉及到了服務的生命周期的概念,接下來我們詳細看一下。
二、服務生命周期
? ?服務的生命周期設置,決定了服務提供容器IServiceProvider使用什么樣的方式提供服務實例對象。正如上面第一章節所說的,
? ?ASP.NET Core服務依賴注入框架,支持三種類型的服務生命周期:
? ?Singleton
? ?Scoped
? ?Transient
? 其中:
? ?Transient:暫時的,每次從服務容器進行請求時創建。?這種生存期適合輕量級、 無狀態的服務。
? ?Singleton:單一實例,在第一次請求時(或者在運行 Startup.ConfigureServices 并且使用服務注冊指定實例時)創建的。每個后續請求都使用相同的實例。
? ?Scoped:范圍內的,作用域生存期服務,以每個客戶端請求(連接)一次的方式創建。可以這么理解:同一個請求中同一個IServiceProvider提供的對象是同一個。
? ?微軟給了個例子不錯:先注冊服務,三種類型
public void ConfigureServices(IServiceCollection services) { <br> services.AddRazorPages(); <br> services.AddScoped<IMyDependency, MyDependency>();services.AddTransient<IOperationTransient, Operation>();services.AddScoped<IOperationScoped, Operation>();services.AddSingleton<IOperationSingleton, Operation>();services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));//OperationService depends on each of the other Operation types.services.AddTransient<OperationService, OperationService>();}第一個請求:??
控制器操作:暫時性:d233e165-f417-469b-a866-1cf1935d2518作用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19單一實例:01271bc1-9e31-48e7-8f7c-7261b040ded9實例:00000000-0000-0000-0000-000000000000OperationService 操作:暫時性:c6b049eb-1318-4e31-90f1-eb2dd849ff64作用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19單一實例:01271bc1-9e31-48e7-8f7c-7261b040ded9實例:00000000-0000-0000-0000-000000000000? ? ?
第二個請求:
第二個請求:控制器操作:暫時性:b63bd538-0a37-4ff1-90ba-081c5138dda0作用域:31e820c5-4834-4d22-83fc-a60118acb9f4單一實例:01271bc1-9e31-48e7-8f7c-7261b040ded9實例:00000000-0000-0000-0000-000000000000OperationService 操作:暫時性:c4cbacb8-36a2-436d-81c8-8c1b78808aaf作用域:31e820c5-4834-4d22-83fc-a60118acb9f4單一實例:01271bc1-9e31-48e7-8f7c-7261b040ded9實例:00000000-0000-0000-0000-000000000000? ?大家可以根據實際的需要選擇服務的生命周期,創建不同類型的服務。
三、服務的消費
? 前面,我們將服務注冊到IServiceCollection,ASP.NET Core服務提供容器IServiceProvider就可以根據IServiceCollection 創建具體類型的服務對象了。
? 我們先看一下IServiceProvider接口,可以發現:只有一個GetService方法。
??
?
? 我們可以通過以下代碼使用:
public static void Main(string[] args) {var builder = CreateHostBuilder(args);var host = builder.Build();var userRepo = host.Services.GetService(typeof(IUserRepository)) as IUserRepository;userRepo.AddUser("user");host.Run();}?同時,我們更多常用的是:
?將服務通過ASP.NET Core依賴注入框架注入到控制器中
?ASP.NET Core MVC 控制器通過構造函數顯式請求依賴關系。即:通過構造函數注入服務的實現。
?前面,我們通過ConfigureServices注冊了服務IUserRepository,在Controller這一層如何消費使用這個服務呢?答案就是在Controller構造函數中注入。
?看一段示例代碼:(HomeController的構造函數中,增加了一個參數IUserRepository)
public class HomeController : Controller {private readonly ILogger<HomeController> _logger;private IUserRepository _userRepository;public HomeController(ILogger<HomeController> logger, IUserRepository userRepository){_logger = logger;_userRepository = userRepository;}public IActionResult Index(){_userRepository.AddUser(new User() { });return View();}public IActionResult Privacy(){return View();}[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]public IActionResult Error(){return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });}}同時,ASP.NET Core MVC 控制器支持通過注解FromServicesAttribute, 將服務直接注入到Action方法中,而無需使用構造函數注入:
public IActionResult Index([FromServices] IUserRepository userRepository) {userRepository.AddUser(new User() { });return View(); }?ASP.NET Core除了支持將服務注入到控制器,同時還支持將服務依賴注入到視圖,可以參考以下鏈接:
? ??https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-3.0
? ? 以上是對ASP.NET Core依賴注入框架的研究,分享給大家。
往期精彩回顧
【.net core】電商平臺升級之微服務架構應用實戰
.Net Core微服務架構技術棧的那些事
Asp.Net Core 中IdentityServer4 授權中心之應用實戰
Asp.Net Core 中IdentityServer4 授權中心之自定義授權模式
Asp.Net Core 中IdentityServer4 授權流程及刷新Token
Asp.Net Core 中IdentityServer4 實戰之 Claim詳解
Asp.Net Core 中IdentityServer4 實戰之角色授權詳解
Asp.Net Core 中間件應用實戰中你不知道的那些事
Asp.Net Core Filter 深入淺出的那些事-AOP
Asp.Net Core EndPoint 終結點路由工作原理解讀
ASP.NET CORE 內置的IOC解讀及使用
總結
以上是生活随笔為你收集整理的ASP.NET Core技术研究-探秘依赖注入框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何查找,修复和避免C#.NET中内存泄
- 下一篇: 从项目到产品: 软件时代需要价值流架构师