最近接觸了 MediatR 這個神奇的工具,只要定義好 request 和 response,以及對應這兩種物件的 handler,在 API 端的程式碼會非常簡潔,詳細可以查CQRS

一開始先看最後的成果:

private readonly ILogger<HomeController> _logger;
private readonly IMediator _mediator;

public HomeController(ILogger<HomeController> logger, IMediator mediator)
{
    _logger = logger;
    _mediator = mediator;
}

public async Task<JsonResult> GetPerson(string name)
{
    GetPersonByNameRequest request =
    new GetPersonByNameRequest
    {
        Name = name,
    };
    var response = await _mediator.Send(request);
    return Json(response);
}

在上面的程式碼中,就只會依賴IMediator這個 interface,在傳統的設計中,通常會依賴多種 service。

接下來看 request 跟 response:

public class GetPersonByNameRequest : IRequest<GetPersonByNameResponse>
{
    public string Name { get; set; } = string.Empty;
}

public class GetPersonByNameResponse
{
    public string ID { get; set; } = Guid.NewGuid().ToString();
    public string Name { get; set; } = string.Empty;
    public int Age { get; set; } = 16;
}

public static class PersonList
{
    public static List<GetPersonByNameResponse> List { get; private set; }

    static PersonList()
    {
        List = new List<GetPersonByNameResponse>
        {
            new GetPersonByNameResponse
            { Age = 16, Name = "Peter" },
            new GetPersonByNameResponse
            { Age = 17, Name = "John" },
            new GetPersonByNameResponse
            { Age = 18, Name = "Marry" },
        };
    }
}

再來是 handler:

public class GetPersonByNameHandler : IRequestHandler<GetPersonByNameRequest, GetPersonByNameResponse>
{
    public async Task<GetPersonByNameResponse> Handle(GetPersonByNameRequest request, CancellationToken cancellationToken)
    {
        string name = request.Name;
        GetPersonByNameResponse response = null;
        await Task.Delay(500);
        response = PersonList.List.Where(p => p.Name == name).FirstOrDefault();
        if (response == null) 
        {
            response = new GetPersonByNameResponse();
        }
        return response;
    }
}

這樣就完成了,而 API 本身不會跟 handler 有任何關係。

最後別忘了在 Program.cs 加上:

builder.Services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly());
});

參考資料