ASP.NET CoreにMediatRを導入する
ASP.NET Core(.NET6)
のWebAPI
のプロジェクトにMediatR
のライブラリを導入したときの作業メモです。
プロジェクト構成
プロジェクト構成です。
Api
層とApplication
層の2つの層があります。
Api
がWebAPI
のプロジェクトで、Application
はクラスライブラリのプロジェクトです。
Api
プロジェクトはApplication
プロジェクトを参照しています。
- ソリューション
- Api
- Controllers
- Api.csproj
- Program.cs
- Application
- Application.csproj
- Api
WebAPI
で受け取ったリクエストに応じて、Application
でいろんな処理を行うため、Application
プロジェクトにMediatR
をインストールします。
パッケージのインストール
以下の2つのパッケージをApplication
プロジェクトにインストールします。
Visual Studio
の場合は「NuGetパッケージの管理」からインストールできます。
VSCode
の場合は以下のURLからdotnet
コマンドなどを確認できます。
MediatR : https://www.nuget.org/packages/MediatR
MediatR.Extensions.Microsoft.DependencyInjection : https://www.nuget.org/packages/MediatR.Extensions.Microsoft.DependencyInjection
アプリケーション層の実装
IRequest
というインターフェースを継承した入力クラスを作成します。
ここではユーザーIDをパラメータにユーザー情報を返す処理を作成します。
IRequest<T>
のT
には出力クラスを指定します。今回はユーザー情報のクラスを設定します。
検索処理は...Query
、更新処理は...Command
と表現することが多いです。
まずは出力クラスを定義します。
UserFindByIdQueryResult.cs
public class UserFindByIdQueryResult
{
public UserFindByIdQueryResult(string id, string name)
{
Id = id;
Name = name;
}
public string Id { get; }
public string Name { get; }
}
次に、入力クラスを定義します。
UserFindByIdQuery.cs
using MediatR;
public class UserFindByIdQuery : IRequest<UserFindByIdQueryResult>
{
public UserFindByIdQuery(string id)
{
Id = id;
}
public string Id { get; }
}
UserFindByIdQuery
クラスに応じた処理を行うHandler
クラスを実装します。
IRequestHandler<入力クラス, 出力クラス>
のインターフェースを継承したクラスを実装します。
このクラスにはHandle
メソッドを実装する必要があります。
public 出力クラス Handler(入力クラス, CancellationToken)
の形でHandle
メソッドを定義します。
UserFindByIdQueryHandler.cs
using MediatR;
public class UserFindByIdQueryHandler : IRequestHandler<UserFindByIdQuery, UserFindByIdQueryResult>
{
private readonly IUserQueryService _queryService;
public UserFindByIdQueryHandler(IUserQueryService queryService)
{
_queryService = queryService;
}
public async Task<UserFindByIdQueryResult> Handle(UserFindByIdQuery query, CancellationToken cancellationToken)
{
return new UserFindByIdQueryResult("1", "ユーザーテスト");
// 実際は以下のようにDBなどから取得することになります。
// return await _queryService.FindById(query.Id);
}
}
作成したHandler
をDIコンテナへ登録します。
Application
プロジェクトにDependencyInjection.cs
というファイルを作成し、DIの処理を追記します。
Handler
クラスを1つづつ登録する方法もありますが、以下のようにすれば、Application
プロジェクト内のすべてのHandler
クラスを登録できます。
DependencyInjection.cs
using System.Reflection;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddMediatR(Assembly.GetExecutingAssembly());
return services;
}
}
Api層の実装
Api
プロジェクトのProgram.cs
に、アプリケーション層のDependencyInjection
の処理を実行するように以下の処理を追加します。
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddApplication();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 以下省略
コントローラーでMediatR
を参照できるようにします。
各コントローラーでコンストラクタインジェクションで参照してもよいですが、今回はコントローラーの基底クラスを作成し、そこでMediatR
を定義します。
ApiControllerBase
using MediatR;
using Microsoft.AspNetCore.Mvc;
[ApiController]
public abstract class ApiControllerBase : ControllerBase
{
private ISender? _mediator;
protected ISender Mediator => _mediator ??= HttpContext.RequestServices.GetService<ISender>()!;
}
各コントローラーでは上記の基底クラスを継承し、MediatR
の処理を実行します。
MediatR.Send(入力クラス)
の形式でメソッドをコールすると、入力クラスに対応するHandler
の処理が実行されます。
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class UserController : ApiControllerBase
{
[HttpGet("{id}")]
public async Task<UserFindByIdQueryResult> FindById(string id)
{
return await Mediator.Send(new UserFindByIdQuery(id));
}
}
以上で導入は完了です。
以下のフォルダ構成になりました。
- ソリューション
- Api
- Controllers
- ApiControllerBase.cs
- UserController.cs
- Api.csproj
- Program.cs
- Controllers
- Application
- Users
- UserFindByIdQuery
- UserFindByIdQuery.cs
- UserFindByIdQueryHandler.cs
- UserFindByIdQueryResult.cs
- UserFindByIdQuery
- Application.csproj
- DependencyInjection.cs
- Users
- Api
MediatR
を使えば、Api
層で受け取ったリクエストを、Application
層に処理をさばくようなイメージで実装できます。