简单學習 .NET CORE MVC 依賴注入(Dependency Injection)

一.概念
剛接觸 .NET CORE MVC ,不習慣但卻非常重要的當屬於依賴注入。與 .Net MVC 對比,.NET CORE MVC 在架構上更傾向靠依賴注入處理對象的傳遞(引用),以前習慣於使用靜態對象、或實例化類等的場景,在.NET CORE MVC 中一般改成從構造函數顯式請求依賴項。

可以說依賴注入 是 .NET CORE MVC 核心,目的在於減少不同對象之間的耦合度,也能大幅提高系統的可測試度,應用程式更易於測試和維護。

為更好解耦,.NET CORE MVC 使用介面,而非直接調用具體對象實體。舉個例子:
使用緩存,過去直接用 MemoryCache.Default就可以了,但在.NET CORE MVC Controller 中要用MemoryCache , 要先在 StartUp註冊服務,然後在 Controller的構造函數中獲取實例,進而在Controller的方法中使用。
另:我們經常會接觸到控制反轉(IOC)概念,但它與依賴注入可以說是同一個概念的不同角度描述。

二.NET CORE MVC 依賴注入的生命週期
這里的生命週期指:透過依賴取得某個元件時,是每次要求得建立一顆新元件,還是從頭到尾共用一個 Instance (執行個體)。
有三種:
1.Singleton(單例)
整個處理只建立一個 Instance,任何時候都共用它。
2. Scoped
在網頁 一個Request 過程(指接到瀏覽器請求到回傳結果前的執行期間)共用一個 Instance。
3. Transient
每次要求元件時就建立一個新的,永不共用。

另注:被註冊到 DI 容器的元件間也會彼此依賴,有個原則是生命週期長的不能參考生命週期比他短的,例如:註冊為 Singleton 的元件不能依賴註冊成 Scoped 的元件, 原因很明顯,如果生命週期比自己短,可能所依賴元件在後期已被消減無法使用。
一般來說,要整個 Process 共用一份的服務可註冊成 Singleton,EF Context (提醒:不要跨進程共用) 建議註冊成 Scoped,以方便 DB 連線重複使用, 若想保險點,註冊成 Transient 就可以了。

三.在.NET CORE MVC 中使用依賴注入
举个简单例子:顯示不同的当前時間格式

public interface IDateTime
{
    DateTime Now { get; }
}
Public class DateTimeFormat1:IDateTime
{
   Public DateTime Now
{
 Return DateTime.Now.Tostring(“yyyy-MM-dd”);
}
}

Public class DateTimeFormat2:IDateTime
{
  Public DateTime Now
 {
       Return DateTime.Now.Tostring(“MM/dd/yyyy”);
 }
}

1.傳統的調用方法

Public class MyController:Controller
{
  Private IdateTime dateTime = New DateTimeFormat1();
  Public IActionResult GetDateTime()
 {
    Rerturn Content(dateTime.Now);
 }
}

以上傳統模式直接NEW 一個具體實例對象(這也是很多初學者或者很多老手最經常使用的方式),如果後期要改變引用的對象,例如日期格式從DateTimeFormat1"—"改為DateTimeFormat2 “///”,那就要在全系統中所有使用該NEW對象的地方更改,代碼耦合度太高,非常不利於維護。

2.使用依賴注入方式
1)在Startup类的ConfigureServices方法中设置注入

public void ConfigureServices(IServiceCollection services)
{ 
    services.AddTransient<IDateTime, DateTimeFormat1>(); 
....
}

2)在Controller 中

public class MyController:Controller
{
    private readonly IdateTime _dateTime; 
    public MyController (IDateTime dateTime) //在構造函數中獲取實例
    {
        _dateTime= dateTime;
    }
    [HttpGet]
   Public IActionResult GetDateTime()
 {
    Rerturn Content(_dateTime.Now);
 }
}

使用依賴注入方時,解決了傳統方式耦合度高的問題,如果後期變更實現,只要在startup.cs中将

 services.AddTransient<IdateTime, DateTimeFormat1>();
 變更成
 services.AddTransient<IdateTime, DateTimeFormat2>()
 即可;

无须在所有使用IdateTime的地方做任何改動;也可以非常簡單的設置生命週期(Transient,Scoped,Singleton);

以上MVC Controller 依赖注入的做法是透過构造函数參數方式,是典型做法。

除此之外,我們也可以有其他方式:
第1種:Action 加上 [FromServices] Attribute ,直接注入到controller的方法,不用構造器注入。

public IActionResult About([FromServices] IDateTime dateTime)
{
    return Content( $"Current server time: {dateTime.Now}");
}

第2種:可以直接在View中獲取注入

例如:@inject IDateTime dateTime
<ul> <li>Now: @dateTime.Now</li> </ul>

第3種:在httpcontext裏直接獲取注入

HttpContext.RequestServices.GetService<IDateTime >();

注意:在 ASP.NET Core 沒有 HttpContext.Current 可用,如果要在 Controller/View 以外使用 HttpContext,要使用 IHttpContextAccessor。
例如:

public class DataService : IDataService
{
    private readonly HttpContext _httpContext;

    public DataService(IHttpContextAccessor contextAccessor)
    {
        _httpContext = contextAccessor.HttpContext;
    }
    //...
}
上一篇:Maven把JAR包引入本地仓库


下一篇:使用Dependency Walker和Process Explorer搞定第三方软件release版本发布问题