0%

為什麼要使用Dependency Injection(依賴注入)? ASP.NET Core 開發者必學!

由於ASP.NET Core 架構上大量地使用依賴注入(Dependency Injection)處理服務物件的傳遞,這確實讓學習難度提高了,算是半強迫性的學習新知識吧,但我認為這是好的。那接下來就來介紹一下究竟為什麼ASP.NET Core要放進這些鬼東西?到底有那些好處呢?

什麼是 IoC (Inversion of Control,控制反轉) ?

用來減低電腦代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI)
例如:「模組都必須依賴於抽象」是 IoC 的一種表現,「實現必須依賴抽象,而不是抽象依賴實現」也是 IoC 的一種表現

什麼是 DI (Dependency Injection,依賴注入)?

DI 是指將一個程式的相依關係改由呼叫它的外部程式來決定的方法。

保留抽象介面,讓組件依賴於抽象介面,當組件要與其它實際的物件發生依賴關係時,藉過抽象介面來注入依賴的實際物件。

使用 DI 的好處

  1. 低耦合,高內聚
  2. 更清晰的意圖
  3. 降低邏輯變更造成改動程式碼的幅度
  4. 關注點分離,提高可測試性

使用 DI 的缺點

系統架構的複雜度增加:我們在寫Code時經常依賴IDE查找引用的功能,對不了解的新手來說,可能會發生找不到實際邏輯到底寫在哪裡的情況,需要多花時間來熟悉框架流程才能上手。

如何注入?

常見的注入方式大約可以分為下列三種:

1. Interface injection
2. Setter injection
3. Constructor injection

假設我們有一個功能,需要拿取得所有使用者的資料,我們可能會寫成如下:

1
2
3
4
5
6
7
8
9
10
public class UserController : Controller
{
[HttpGet]
public IActionResult GetUserList()
{
UserRepository userRepository = new UserRepository();
var userList = userRepository.GetUserList();
return Json(userList);
}
}

然後我們嘗試將new拿掉,改用注入的方式,就可以變成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UserController : Controller
{
private UserRepository _userRepository;

// Constructor injection
public UserController(UserRepository userRepository) {
this._userRepository = userRepository;
}

// Setter injection
public void SetUserRepository(UserRepository userRepository) {
this._userRepository = userRepository;
}

[HttpGet]
public IActionResult GetUserList()
{
var userList = _userRepository.GetUserList();
return Json(userList);
}
}

接下來,依照不同的DI Framework,注入UserRepository實際的Instance即可。

C#常見的DI Framework

ASP.NET Core 中的注入

ASP.NET Core 的架構基於DI之上,如果從.NET Framework跳到 .Net Core 的話,DI的學習是必經之路。

然而 ASP.NET Core 的 DI 是採用 Interface injection + Constructor Injection

在 Startup.ConfigureServices中,
我們可以註冊三種不同的選項:

1. Singleton
    整個 Process 只建立一個 Instance,任何時候都共用它。
2. Scoped
    在網頁 Request 處理過程(指接到瀏覽器請求到回傳結果前的執行期間)共用一個 Instance。
3. Transient
    每次要求就建立一個新的,永不共用。

下面是三種選項的註冊方式,依照不同的情境選一種使用即可,通常最常使用的是Scoped。

Startup.cs

1
2
3
4
5
6
7
8
9
10
11
12
public void ConfigureServices(IServiceCollection services)
{
// Singleton
services.AddSingleton<IUserRepository, UserRepository>();
// Scoped
services.AddScoped<IUserRepository, UserRepository>();
// Transient
services.AddTransient<IUserRepository, UserRepository>();

//通用寫法
services.Add(new ServiceDescriptor(typeof(IUserRepository), typeof(UserRepository), ServiceLifetime.Transient));
}

註冊完我們就可以再Controller中使用囉

UserController.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UserController : Controller
{
private IUserRepository _userRepository;

public UserController(IUserRepository userRepository) {
this._userRepository = userRepository;
}

[HttpGet]
public IActionResult GetUserList()
{
var userList = _userRepository.GetUserList();
return Json(userList);
}
}

心得

其實在職場中待久了,經常會看見一些專案會使用DI的Framework,但又或許是因為交接不完全和開發者參差不齊的原因,經果一陣子了人員調動後,專案常常就會有四不像的情形發生,有些地方用了DI,又有些地方總是一直在new物件。希望這篇能讓新手了解一些觀念,往後看到DI的東西也不太恐懼,先多看看文件在動手吧!別破壞了原有的好架構。

參考

ASP.NET Core Dependency Injection Deep Dive

為什麼要用 Dependency Injection

↓↓↓ 如果喜歡我的文章,可以幫我按個Like! ↓↓↓
>> 或者,請我喝杯咖啡,這樣我會更有動力唷! <<<
街口支付

街口支付

街口帳號: 901061546

歡迎關注我的其它發布渠道