.Net Core3.0依賴注入DI

原文: .Net Core3.0依賴注入DI

構建ASP.NET Core應用程序的時候,依賴注入已成爲了.NET Core的核心,這篇文章,咱們理一理依賴注入的使用方法。html

不使用依賴注入

 首先,咱們建立一個ASP.NET Core Mvc項目,定義個表達的愛服務接口,中國小夥類實現這個類以下:設計模式

複製代碼
public interface ISayLoveService
    {
        string SayLove();
    }

 public class CNBoyService : ISayLoveService
    {
        public string SayLove()
        {
            return "安紅,我喜歡你";
        }
    }
複製代碼

在LoveController 控制器中調用 ISayLoveService的SayLove方法。框架

複製代碼
public class LoveController : Controller

    {       
       private  ISayLoveService loveService;     
       public IActionResult Index()
        {
            loveService = new CNBoyService(); //中國小夥對安紅的表達
            ViewData["SayLove"] = loveService.SayLove();    
            return View();
        }
    }
複製代碼

輸出如圖:ide

 

小結:LoveController控制器調用ISayLoveService服務的SayLove方法;咱們的作法,直接在控制器去new CNBoyService()實例對象,也就是LoveController依賴ISayLoveService類。函數

思考:能不能有種模式,new實例不要在使用的時候進行建立,而是在外部或者有一個容器進行管理;這不就是ioc思想嗎?好處,代碼的解耦、代碼更好的維護等等。測試

使用依賴注入

上面的疑惑,答案是確定的,有!而且ASP.NET Core 支持依賴關係注入 (DI) 軟件設計模式(固然也能夠兼容第三方)。咱們還使用上面的代碼,ui

服務註冊

 在Startup類ConfigureServices方法中註冊服務容器中的依賴關係this

複製代碼
  public void ConfigureServices(IServiceCollection services)

        {
            services.AddSingleton<ISayLoveService, CNBoyService>();
            services.AddControllersWithViews();
        }
複製代碼

 在LoveControlle控制器中,經過構造函數注入spa

複製代碼
 private readonly  ISayLoveService loveService;  
public LoveController(ISayLoveService loveService)
{

this.loveService = loveService; }

public IActionResult Index() {
ViewData[
"SayLove"] = loveService.SayLove();

return View(); }
複製代碼

LoveController 正在將ISayLoveService做爲依賴項注入其構造函數中,而後在Index方法中使用它。設計

推薦:

  • 將注入的依賴項分配給只讀字段/屬性(以防止在方法內部意外爲其分配另外一個值)。

  • 使用接口或基類抽象化依賴關係實現。

小結:在控制器中,還有幾種使用如:[FromServices] 標籤 、 HttpContext.RequestServices.GetService<T>();咱們發現可使用ASP.NET Core 提供了一個內置的服務容器 IServiceProvider。服務只須要在Startup.ConfigureServices 方法中註冊,而後在運行時將服務注入 到使用它的類的構造函數中。 框架負責建立依賴關係的實例,並在再也不須要時對其進行處理。

思考:服務註冊的時候使用的是 AddSingleton,如services.AddSingleton<ISayLoveService, CNBoyService>();還有其餘的嗎?

服務生命週期

服務註冊的時候,ASP.NET Core支持指定三種生命週期如:

  1. Singleton 單例

  2. Scoped 範圍

  3. Transient 短暫的

Singleton 僅建立一個實例。該實例在須要它的全部組件之間共享。所以始終使用同一實例。

Scoped 每一個範圍建立一個實例。在對應用程序的每一個請求上都會建立一個範圍,所以每一個請求將建立一次註冊爲Scoped的任何組件。

Transient 在每次被請求時都會建立,而且永不共享。

爲了可以更好的裂解生命週期的概念,咱們把上面代碼稍做改動,作一個測試:

ISayLoveService 新增個屬性LoveId,類型爲guid,

複製代碼
public interface ISayLoveService
    {
        Guid LoveId { get; }
        string SayLove();
    }
    public interface ITransientSayLoveService : ISayLoveService
    {
    }
    public interface IScopedSayLoveService : ISayLoveService
    {
    }
    public interface ISingletonSayLoveService : ISayLoveService
    {
    }
    public interface ISingletonInstanceSayLoveService : ISayLoveService
    {
    }
複製代碼

 BoyService也很簡單,在構造函數中傳入一個Guid,並對它進行賦值。

複製代碼
public class BoyService : ITransientSayLoveService,
        IScopedSayLoveService,
        ISingletonSayLoveService,
        ISingletonInstanceSayLoveService
    {
        public BoyService():this(Guid.NewGuid()) { }
        public BoyService(Guid id)
        {
            LoveId = id;
        }
        public Guid LoveId { get; private set; }

        public string SayLove()
        {
            return LoveId.ToString();
        }
    }
複製代碼

 每一個實現類的構造函數中,咱們都產生了一個新的guid,經過這個GUID,咱們能夠判斷這個類到底從新執行過構造函數沒有.

服務註冊代碼以下:

複製代碼
   public void ConfigureServices(IServiceCollection services)
        {
            //生命週期設置爲Transient,所以每次都會建立一個新實例。
            services.AddTransient<ITransientSayLoveService, BoyService>();
            services.AddScoped<IScopedSayLoveService, BoyService>();
            services.AddSingleton<ISingletonSayLoveService, BoyService>();
            services.AddSingleton<ISingletonInstanceSayLoveService>(new BoyService(Guid.Empty));

            services.AddControllersWithViews();
        }
複製代碼

在LifeIndex方法中屢次調用ServiceProvider的GetService方法,獲取到的都是同一個實例。

複製代碼
  public IActionResult LifeIndex()
        {
            ViewData["TransientSayLove1"] = HttpContext.RequestServices.GetService<ITransientSayLoveService>().SayLove();
            ViewData["ScopedSayLove1"] = HttpContext.RequestServices.GetService<IScopedSayLoveService>().SayLove();
            ViewData["SingletonSayLove1"] = HttpContext.RequestServices.GetService<ISingletonSayLoveService>().SayLove();
            ViewData["SingletonInstanceSayLove1"] = HttpContext.RequestServices.GetService<ISingletonInstanceSayLoveService>().SayLove();
            //同一個HTTP請求 ,在從容器中獲取一次
            ViewData["TransientSayLove2"] = HttpContext.RequestServices.GetService<ITransientSayLoveService>().SayLove();
            ViewData["ScopedSayLove2"] = HttpContext.RequestServices.GetService<IScopedSayLoveService>().SayLove();
            ViewData["SingletonSayLove2"] = HttpContext.RequestServices.GetService<ISingletonSayLoveService>().SayLove();
            ViewData["SingletonInstanceSayLove2"] = HttpContext.RequestServices.GetService<ISingletonInstanceSayLoveService>().SayLove();

            return View();
        }
複製代碼

咱們編寫view頁面,來展現這些信息以下:

複製代碼
@{
    ViewData["Title"] = "LifeIndex";
}

    <div class="row">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Operations</h2>
            </div>
            <div class="panel-body">
                <h3>獲取第一次</h3>
                <dl>
                    <dt>Transient1</dt>
                    <dd>@ViewData["TransientSayLove1"] </dd>
                    <dt>Scoped1</dt>
                    <dd>@ViewData["ScopedSayLove1"]</dd>
                    <dt>Singleton1</dt>
                    <dd>@ViewData["SingletonSayLove1"] </dd>
                    <dt>Instance1</dt>
                    <dd>@ViewData["SingletonInstanceSayLove1"]</dd>
                </dl>
                <h3>獲取第二次</h3>
                <dl>
                    <dt>Transient2</dt>
                    <dd>@ViewData["TransientSayLove2"]</dd>
                    <dt>Scoped2</dt>
                    <dd>@ViewData["ScopedSayLove2"]</dd>
                    <dt>Singleton2</dt>
                    <dd>@ViewData["SingletonSayLove2"]</dd>
                    <dt>Instance2</dt>
                    <dd>@ViewData["SingletonInstanceSayLove2"]</dd>
                </dl>
            </div>
        </div>
    </div>
複製代碼

運行代碼第一次輸出:

咱們發現,在一次請求中,發現單例、範圍的生命週期的guid 沒有變化,說明分別用的是同一個對象,而瞬態guid不一樣,說明對象不是一個。

刷新以後,查看運行效果

咱們發現經過刷新以後,單例模式的guid仍是跟首次看到的同樣,其餘的都不一樣;

總結:若是您將組件A註冊爲單例,則它不能依賴已註冊「做用域」或「瞬態」生存期的組件。通常而言:組件不能依賴壽命短於其壽命的組件。若是默認的DI容器不能知足項目需求,能夠替換成第三方的如功能強大的Autofac。

相關文章
相關標籤/搜索