問題來了,為什麼 Blazor 會知道 WeatherForecastService 在這裡可以呼叫?
點開 Program.cs,可以找到一行程式碼:
builder.Services.AddSingleton<WeatherForecastService>();
把這段程式碼註解,重新載入網頁,點擊 Fetch data 選單,可以在頁面看到下面的異常警告資訊(只在頁尾顯示了一個警告區塊),詳細警告看終端機輸出,因為我們試圖在 FetchData.razor 呼叫 WeatherForecastService,卻沒告訴 Blazor 我們要註冊這個服務。


複製提示看看,這個提示很明確:
Cannot provide a value for property 'ForecastService' on type 'BlazorServer.Pages.FetchData'. There is no registered service of type 'BlazorServer.Data.WeatherForecastService'.
不過這並不是 day03 說到的依賴注入,依賴注入的目的是擺脫高層級程式必須依賴於低層級程式的窘境,以減少耦合性。舉例來說,如果今天 FetchData.razor 要呼叫其他 Service,例如 NewWeatherForecastService 的同名方法 GetForecastAsync,取回 10 筆資料,那只要用到 WeatherForecastService 的地方都必須修改,目前因為 Demo 的關係不多所以沒感覺,如果日後有 10 幾 20 幾個地方要改呢?
這時候就是依賴注入發揮功能的時候了,先定義一個介面:interface IWeatherForecastService
namespace BlazorServer.Data;
public interface IWeatherForecastService
{
Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
}
裡面就寫我們要的方法:Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
也不用實作(雖然介面也能實作:站長註:在C# 8.0中,針對介面引入了一項新特性,就是可以指定預設實作,方便對已有實作進行擴充,也對面向Android和Swift的API進行互操作提供了可能性。),接著讓 WeatherForecastService 跟 NewWeatherForecastService 繼承 IWeatherForecastService

Program.cs 改用 IWeatherForecastService 跟 NewWeatherForecastService 註冊

看上面截圖,在 FetchData.razor 中,也改為注入 IWeatherForecastService
重整載入網頁就能看到資料筆數變為 10 筆了

依賴注入的核心就是「對某個功能的依賴性是透過注入的方式」,不直接呼叫底層程式,而是呼叫底層程式的介面,即便底層程式修改也不會導致所有呼叫該程式的呼叫端都必須改動。
註:由於筆者是在寫完這篇之後才想起來生命週期,原本想用 git rebase 的功能回到這一次的 commit 新增 Demo,但會有 git 斷頭疑慮,所以筆者會在 day 07 再說明生命週期,若有不便敬請見諒。
註:本文程式碼透過 .NET 6 + Visual Studio 2022 重構,可點擊原文連結與重構後程式碼比較學習,謝謝閱讀,支援原作者