BlazorのDI(依存性注入)とは?サービスの登録と使い方入門|ASP.NET×Blazor入門 8.1

8.1 DIの基本と登録方法(builder.Services.Add...)

Blazorでは、ASP.NET Coreと同様に依存性注入(Dependency Injection:DI)の仕組みが組み込まれており、 サービス(ビジネスロジックや状態管理クラスなど)をコンポーネントや他のサービスに自動的に渡すことができます。 DIを正しく活用することで、疎結合でテストしやすいコードが書けるようになり、アプリケーションのメンテナンス性が大きく向上します。

依存性注入とは?

依存性注入とは、必要なサービス(依存オブジェクト)を、使用する側(コンポーネントやクラス)が自ら生成するのではなく、 外部から注入するという設計手法です。たとえば、データ取得処理などのロジックを、コンポーネント内部ではなく 「WeatherService」などの外部クラスに分離し、そのクラスのインスタンスをDI経由で受け取って利用します。

サービスの定義例

たとえば、外部に以下のようなサービスクラス WeatherService があるとします:


// WeatherService.cs
public class WeatherService
{
    private readonly HttpClient _http;

    public WeatherService(HttpClient http)
    {
        _http = http;
    }

    public async Task<WeatherInfo[]> GetForecastAsync()
    {
        return await _http.GetFromJsonAsync<WeatherInfo[]>("sample-data/weather.json")
               ?? Array.Empty<WeatherInfo>();
    }
}
  

サービス登録の方法

Blazor Server や Blazor WebAssembly では、以下のようにサービスを登録します:


// Program.cs

builder.Services.AddSingleton<WeatherService>();
builder.Services.AddScoped<UserState>();
builder.Services.AddTransient<ILogger, ConsoleLogger>();
  

ライフタイムの違いは重要です:

  • Singleton: アプリケーション全体で1つのインスタンス。設定情報やキャッシュなど。
  • Scoped: Blazor Serverでは「接続ごと」に1インスタンス。ユーザーごとの状態に適します。
  • Transient: 利用のたびに新しいインスタンスが生成されます。ステートレスなサービス向き。

サービスの注入と利用方法

登録したサービスは、Razor コンポーネントや他のサービスから次のように注入できます。

① Razor コンポーネントでの利用(@inject ディレクティブ)


@inject WeatherService WeatherService

@code {
    private WeatherInfo[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await WeatherService.GetForecastAsync();
    }
}
  

② コンストラクタインジェクション(クラス間の依存)

サービス同士で依存する場合、コンストラクタ経由で注入します。例えば、MyComponentServiceWeatherService に依存している場合:


public class MyComponentService
{
    private readonly WeatherService _weatherService;

    public MyComponentService(WeatherService weatherService)
    {
        _weatherService = weatherService;
    }

    public async Task<string> GetMessageAsync()
    {
        var data = await _weatherService.GetForecastAsync();
        return $"今日は {data.First().Summary} の予報です";
    }
}
  

このように、サービスを外部に定義し、それを必要に応じて注入することで、ロジックの再利用やテストが格段に容易になります。

補足:HttpClientの使い方(WASMの場合)

Blazor WebAssemblyでは HttpClient を使用する際に注意が必要です。以下のように、APIエンドポイントのBaseAddressを明示して登録します:


// Program.cs (Blazor WebAssembly)
builder.Services.AddScoped(sp =>
    new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
  

このように正しくDIとライフタイムを理解して活用することで、Blazorアプリはより堅牢で柔軟な構造になります。

次のセクションでは、ScopedとSingletonの違いにより、サービスの動作がどのように変化するかを具体的に見ていきましょう。 「8.2 Scoped vs Singleton の違い」へ進みます。

2025-05-04

下田 昌平

開発に関するインプットをアウトプットしています。