iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
1

終於要來講解相依性注入(dependency injection),一起來看看如何在 Blazor WebAssembly 中使用相依性注入吧!


相依性注入技術,可以說是當今 .NET Core 開發人員的必備技能,網路上也充斥著大量技術文章,避免有人還沒上車,就小小的聊一下,如果已經了解 DI 的人可以下滑至下個段落,或者可以看一下我理解對不對。

相依性注入簡單來說就是將物件的生命週期集中管理,這使得本來相依的兩個物件被迫分開,因為相依物件的生命週期從物件本身管理被改成由 DI Container 管理。當物件需要相依物件時,也需要從 DI Container 去要,而將相依物件放進 DI Container 與物件從 DI Container 取得相依物件,這整件事情,我們稱作相依性注入。

那麼為什麼會有相依性注入?我個人認為,是因為現在程式碼撰寫風格的變化,以前可能電腦沒那麼先進,所以對於系統的負擔錙銖必較,但現在除非是特定產業,不然細微的效能差異並不會影響使用者體驗,也造就了可讀性與可維護性較高的程式碼成為了現在的主流,當然也包括可測試性的程式碼,而這些程式碼都有個共通點,那就是符合 SOLID (物件導向設計) 的五大原則,而其中 D(依賴反轉原則) 的實現就是相依性注入。

因為我本人寫程式的資歷並不多,對於發展史也是東拼西湊,如果有誤導大眾瞎說了一堆還請提出,感謝。

Blazor WebAssembly 中使用相依性注入

相依性注入可以:

  1. 使多個元件間共用服務類別的單一實例(稱為單一服務)。

  2. 將元件與具體的服務類別間的參考變成抽象,也就是透過介面從 DI Container 中取得該介面的實作,使得我們可以交換實作來撰寫單元測試,也就是 Mock 的技巧。

在 Blazor WebAssembly 中的服務生命週期有:

存留期 描述
Scoped Blazor WebAssembly 應用程式目前不具有 DI 範圍的概念,註冊為 Scoped 的服務也會表現得像 Singleton,這點要注意,因為跟其他的 .net 框架有點差異。但官方建議如果你覺得該使用 Scoped 的服務還是使用 Scoped 吧!
Singleton DI 會建立服務的單一實例,所有需要此服務的元件都會得到相同的實例。
Transient 每當元件從服務容器取得服務的實例時,都會收到服務的新實例

而 Blazor WebAssembly 提供了幾個預設服務:

服務 存留期 描述
HttpClient Scoped 提供方法來傳送 HTTP 要求與接收 HTTP 回應,會使用瀏覽器來處理背景中的 HTTP 流量。
IJSRuntime Singleton 當 JavaScript 呼叫被派遣時,此實例代表 JavaScript Runtime。
NavigationManager Singleton 包含使用 URIs 和導覽狀態的協助程式。

而在元件中注入服務的方式有兩種:

  1. 透過 @inject 指示詞注入如:
@inject HttpClient HttpClient
  1. 透過 [Inject] 屬性注入,一般而言不會這樣使用,除非是注入在基類元件,使得衍生元件不需要再注入。
[Inject]
protected HttpClient HttpClient { get; set; }

而在服務中注入其他服務,只能透過建構式注入如:

public class DataAccess : IDataAccess
{
    public DataAccess(HttpClient client)
    {
        // ...
    }
}

且要符合以下條件:

  1. 必須要有一個建構式,其引數可由 DI 完成,如果有指定預設值,則允許包含 DI 未涵蓋的其他參數。

  2. 適用的建構式必須是 public

  3. 一定要有一個是用的建構式,也就是 DI 在 new 的時候不能有某引數不在 DI Container 內而導致 new 失敗,此時 DI 就會擲回例外狀況。

將服務新增到 DI

若是想要將自己的服務放到 DI,只需要修改 Program.cs 檔案中的 Main 方法即可。

透過 builder.Services 並根據服務的生命週期來選擇對應的方法即可:

public class Program
{
  public static async Task Main(string[] args)
  {
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("app");
    builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
    builder.Services.AddSingleton<IMyDependency, MyDependency>();
    await builder.Build().RunAsync();
  }
}

如上我放入了一個介面為 IMyDependency 實例為 MyDependency 的服務,並且生命週期為 Singleton,這樣就完成基本的 DI 了。


以上就是關於在 Blazor WebAssembly 使用相依性注入的簡單介紹,是不是很簡單呀?

感謝大家的閱讀,我們明天見。

參考資料
ASP.NET Core Blazor 相依性注入
SOLID (物件導向設計)


上一篇
魔術技巧 - 版型配置
下一篇
魔術技巧 - HTTP 要求與回應
系列文
大內魔術 Blazor - 誰說前端一定要寫JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言