So why does Blazor know that WeatherForecastService can be called here?
Open Program.cs and you’ll find the following line:
builder.Services.AddSingleton<WeatherForecastService>();
If you comment out this line, reload the page, and click the Fetch data menu, you’ll see an exception warning in the page (only a warning block appears in the footer). For detailed warnings, check the terminal output — because we’re trying to call WeatherForecastService in FetchData.razor, but we haven’t told Blazor to register this service.


Let’s copy that warning for clarity:
Cannot provide a value for property 'ForecastService' on type 'BlazorServer.Pages.FetchData'. There is no registered service of type 'BlazorServer.Data.WeatherForecastService'.
But this isn’t about dependency injection as discussed in day03. The purpose of dependency injection is to free high-level programs from depending on low-level programs, reducing coupling. For example, if FetchData.razor needs to call another service, like NewWeatherForecastService with the same method name GetForecastAsync, and retrieve 10 records, then everywhere that uses WeatherForecastService must be updated. In this small demo it might not feel like a big deal, but what if there are 10 or 20 places to change?
That’s where dependency injection shines. First, define an interface: IWeatherForecastService
namespace BlazorServer.Data;
public interface IWeatherForecastService
{
Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
}
Inside, we write the method we need: Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
There’s no implementation yet (though interfaces can have default implementations — Editor’s note: C# 8.0 introduces default implementations for interfaces, making it easier to extend existing implementations and enabling interop with Android and Swift APIs.). Then we make WeatherForecastService and NewWeatherForecastService implement IWeatherForecastService.

In Program.cs, we register IWeatherForecastService with NewWeatherForecastService.

As shown in the screenshot above, in FetchData.razor, we also change the injection to IWeatherForecastService.
After refreshing the page, you’ll see the data count becomes 10 records.

The core of dependency injection is that “dependence on a certain functionality is injected.” Instead of directly calling the low-level program, we call its interface. Even if the low-level program changes, all callers that rely on it don’t have to be modified.
Note: The author intended to explain the lifecycle after writing this article and originally planned to use git rebase to go back to this commit and add a demo, but that could lead to a detached HEAD issue. Therefore, the lifecycle will be explained on day 07. Apologies for any inconvenience.
Note: The code in this article has been refactored using .NET 6 and Visual Studio 2022. You can click the original link to compare the refactored code with the original. Thank you for reading, and please support the original author.