ASP.NET Core 練習 - 依賴注入 DI 我們知道 ASP.NET Core 已全面使用依賴注入管理物件生命週期,Model、Controller 要使用服務,或是服務 A 要使用服務 B,都要透過 DI 容器取得服務的執行個體(Instance),而非自己 new 一個出來用。而使用 DI 容器取得服務物件的最標準做法是在建構式宣告該服務型別的參數,並將其存成私有變數供後續使用。

前陣子跟人閒聊到這個,不免聽到一些抱怨(謎:這個人閒暇時間到底都跟哪些人在聊什麼?),說原本 new 一下就可以用,為什麼非得扯到建構式,還要宣告 private 變數 Blah Blah...

舉例來說,我想建立一個 MyService,其中會使用 IConfiguration 讀取 appsettings.json 設定值以及引用自訂的 IWeatherService。

在 Visual Studio 新增類別 MyService.cs,一開始的空殼會像這樣:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MvcLab.Models
{
    public class MyService
    {
    }
}

若依 ASP.NET Core DI 的標準做法,應該要寫成這樣:

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MvcLab.Models
{
    public class MyService
    {
        private readonly IConfiguration configuration;
        private readonly IWeatherService weatherService;

        public MyService(IConfiguration configuration, IWeatherService weatherService)
        {
            this.configuration = configuration;
            this.weatherService = weatherService;
        }
    }
}

看起來是有點費工,但我們可以善用 Visual Studio 2019 的強大功能快速寫出來。以下是步驟:

  1. 輸入 ctor 按兩次 Tab 鍵

    ctor Snippet 會建出空白建構式
  2. 在 MyService() 中輸入 IConfiguration,下方出現紅蚯蚓時按 Alt-Enter 魔法鍵,VS 會問你要不要加入 using Microsoft.Extensions.Configuration 或在 IConfiguration 前方加上完整命名空間改成 Microsoft.Extensions.Configration.IConfiguration:

    選擇 using 按 Enter 後,VS 會在最上方加入 using Microsoft.Extensions.Configuration,紅蚯蚓消失。
  3. 在 IConfiguration 後方敲一個空白,VS 很貼心,深知不知怎麼取名字是程式設計師心中的痛,如果不想花腦筋,按向下鍵加 Enter,讓 VS 自動幫你把名字想好。
  4. 稍等一秒,等 VS 自動選取變數名稱 configuration 變成橄欖綠底,按下 Alt-Enter,VS 會詢問要不要把它轉成 Property 或 Field:

    選擇 Create and initialize field 'configuration',一個字也不用敲程式就寫好了。
  5. 如法炮製,IWeatherService 比照處理,IWeatherService 的建議變數名稱較多,有 weatherService、weather、service 可選,我選 weather:

    最終成品

瞧,是不是比純手工敲輕鬆多了?

ASP.NET Core 大量採用 DI 概念改變了引用元件或服務的程式寫法,比傳統 new 完就用要寫比較多的程式碼,但這是享受 DI 優點要付出的代價,而在地表最強開發工具的加持下,要花的功夫其實沒想像多,大家就勇敢擁抱它吧!

Tips of how to use VS2019 Snippet and refactor feature to create constructor with DI arguments.


Comments

# by Yuhau

大大您好,想請教一下: 以您的範例MyService這個class來看的話,建構式裡傳入IConfiguration和IWeatherService兩個參數, 我的問題是如果這個class底下的A Method只需用到IConfiguration、B Method只需要用到IWeatherService、C Method的話IConfiguration、IWeatherService兩個都會使用到。 那我是否需多加n個建構式只傳IConfiguration、只傳IWeatherService...等? 那這樣的話建構式會很多個,可能會造成維護上的困擾。 或是如果只放一個建構式,一次寫入全部需要使用到的物件,那這樣的話可能宣告時就傳入多餘的物件。 請問大大是否有什麼建議的作法或方向嗎? 謝謝。

# by Jeffrey

to Yuhau, 依 ASP.NET Core 標準作法,Controller 或其他用到 MyService 的服務會透過 DI 取得 MyService 物件,不需要自己呼叫建構式,也太有準備參數的困擾。除非你有部分程式碼不是用 DI,需要自己 new MyService(),依你說的情境,我不會為此宣告多個建構式增加複雜度,若非常確定 A Method 不會用到 IWeatherService 而且建立的 MyService 只會用到 A Method,呼叫建構式時 IConfiguration 傳 null 即可。

Post a comment