使用 MediatR 實作 API 邏輯
最近接觸了 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());
});
參考資料