ASP.NET Core技術研究-探祕依賴注入框架

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

  https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=dotnet-plat-ext-3.13d

  經過這個接口和類實現,咱們能夠發現,註冊服務其實就是將一個服務的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服務依賴注入框架,支持三種類型的服務生命週期:

  •    Singleton
  •    Scoped
  •    Transient

  其中:

   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

相關文章
相關標籤/搜索