zukucode
主にWEB関連の情報を技術メモとして発信しています。

ASP.NET Core DIでサービスをControllerから使用する

DIは、クラスが必要とする別のクラスを外部から渡す仕組みです。

ASP.NET CoreにはDIコンテナーが標準で用意されています。

DIを使う理由は、単にnewを書く場所を移すためではありません。Controllerが具象クラスの生成方法や寿命を決めず、必要な機能だけを宣言できるようにするためです。これにより、本番用の実装とテスト用の実装を呼び出し側を変えずに交換できます。

サービスを作成する

GreetingService.cs
public interface IGreetingService
{
    string CreateMessage(string name);
}

public sealed class GreetingService : IGreetingService
{
    public string CreateMessage(string name)
    {
        return $"こんにちは、{name}さん。";
    }
}

interfaceには利用できる処理を定義し、classへ実際の処理を書きます。

DIコンテナーへ登録する

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddScoped<IGreetingService, GreetingService>();

var app = builder.Build();
app.MapControllers();
app.Run();

IGreetingServiceが必要な場所へ、GreetingServiceを渡す設定です。

Controllerで受け取る

GreetingController.cs
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/greeting")]
public sealed class GreetingController(IGreetingService greetingService)
    : ControllerBase
{
    [HttpGet]
    public IActionResult Find([FromQuery] string name)
    {
        return Ok(new
        {
            message = greetingService.CreateMessage(name),
        });
    }
}

GET /api/greeting?name=山田へアクセスすると、Controllerの作成時にサービスが自動で渡されます。

Controller内でnew GreetingService()を書く必要はありません。

登録方法の違い

登録時には、依存するオブジェクトをいつまで共有するかも決めます。寿命が長いほど効率的とは限らず、リクエスト固有の状態をSingletonへ持たせると、別の利用者の処理と共有される危険があります。

登録方法インスタンスの期間
AddTransient取得するたびに新しく作る
AddScoped1回のHTTPリクエスト内で共有する
AddSingletonアプリケーション全体で共有する

Web APIのサービスやデータベース関連では、まずAddScopedを使うことが多いです。

Singletonはアプリケーション全体で残るため、寿命が短いScopedのサービスをコンストラクターで受け取る設計は避けます。

DIを使うと、クラス内で依存先を作成せずに済み、実装の交換やテストがしやすくなります。


関連記事