ASP.NET Core在底層內置了一個依賴注入框架,經過依賴注入的方式註冊服務、提供服務。依賴注入不只服務於ASP.NET Core自身,同時也是應用程序的服務提供者。編程
絕不誇張的說,ASP.NET Core經過依賴注入實現了各類服務對象的註冊和建立,同時也實現了面向抽象的編程模式和編程體驗,提高了應用程序的擴展性。api
今天,咱們普及一下ASP.NET Core中依賴注入的一些基本知識。mvc
1、服務的註冊框架
咱們經過建立一個ASP.NET Core的項目,能夠發如今Startup.cs 類中,有一個方法ConfigureServices,這個方法的註釋是這樣的:ide
This method gets called by the runtime. Use this method to add services to the container.函數
在ConfigureServices方法中咱們能夠將經過ASP.NET Core內置的依賴注入框架實現服務的的註冊。ui
這個方法有個參數:IServiceCollection,見名知意,服務集合。this
ASP.NET Core內置的依賴注入框架將服務註冊信息存儲到一個實現了IServiceCollection接口的對象中。默認狀況下這個接口的實現類是ServiceCollection,如下是這個類的說明:spa
經過這個接口和類實現,咱們能夠發現,註冊服務其實就是將一個服務的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服務提供容器
服務註冊提供了一系列重載的方法,你們能夠根據須要進行選擇:
服務註冊的過程當中,涉及到了服務的生命週期的概念,接下來咱們詳細看一下。
2、服務生命週期
服務的生命週期設置,決定了服務提供容器IServiceProvider使用什麼樣的方式提供服務實例對象。正如上面第一章節所說的,
ASP.NET Core服務依賴注入框架,支持三種類型的服務生命週期:
其中:
Transient:暫時的,每次從服務容器進行請求時建立。 這種生存期適合輕量級、 無狀態的服務。
Singleton:單一實例,在第一次請求時(或者在運行 Startup.ConfigureServices 而且使用服務註冊指定實例時)建立的。每一個後續請求都使用相同的實例。
Scoped:範圍內的,做用域生存期服務,以每一個客戶端請求(鏈接)一次的方式建立。能夠這麼理解:同一個請求中同一個IServiceProvider提供的對象是同一個。
微軟給了個例子不錯:先註冊服務,三種類型
public void ConfigureServices(IServiceCollection services) {
services.AddRazorPages();
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-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
你們能夠根據實際的須要選擇服務的生命週期,建立不一樣類型的服務。
3、服務的消費
前面,咱們將服務註冊到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依賴注入框架的研究,分享給你們。
周國慶
2020/4/12