依赖注入的三种方式_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)
{
services.AddRazorPages();
services.AddScoped();
services.AddTransient();
services.AddScoped();
services.AddSingleton();
services.AddSingleton(new Operation(Guid.Empty));
//OperationService depends on each of the other Operation types.
services.AddTransient();
}
第一個請求:
控制器操作:
暫時性:d233e165-f417-469b-a866-1cf1935d2518
作用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19
單一實例:01271bc1-9e31-48e7-8f7c-7261b040ded9
實例:00000000-0000-0000-0000-000000000000
OperationService 操作:
暫時性: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-000000000000
OperationService 操作:
暫時性: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 _logger;
private IUserRepository _userRepository;
public HomeController(ILogger 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依賴注入框架的研究,分享給大家。
總結
以上是生活随笔為你收集整理的依赖注入的三种方式_ASP.NET Core技术研究-探秘依赖注入框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么只有三次挥手_TCP为什么是三次握
- 下一篇: jsonhandle主界面没有显示格式_