为什么要在.Net Core中使用MediatR library?
MediatR libray 是一款比较优秀的中介者/调停者实现组件,在github上有3000多个星,算是比较成功的组件。最大的特点是基于内存的消息传递,而且不用依赖其他组件。其作者是大名鼎鼎的Jimmy Bogard(AutoMapper的作者)。在这篇文章,我将尝试解释为什么要在我们的项目中引用此组件。
1)更轻的控制器
下面是一种通用的控制器代码实现,相信很多人都写过或见过这样的代码:
1 public async Task<Response> Create([FromBody] Request request) 2 { 3 var isValid = _validator.Validate(request); 4 if (!isValid) return _responseBuilder.BuildBadRequest(); 5 6 var dto = _mapper.Map<ObjectDto, Request>(request); 7 8 var result = await _repository.Create(dto); 9 return _responseBuilder.Success(result); 10 }
你可能会想:没啥问题啊?大家不都是这样做的么,先验证,然后映射,最后保存,然后将结果返回给客户,没毛病。
当然,这样做确实没毛病,但是其实我们可以做的更好。
我认为控制器只是一个路由转发,它最好只接受客户的请求,然后让其他handler去处理,结束后将结果再转发给客户。像验证、映射、保存等业务完全可以交由其他的代码去处理,这样才符合标准流程。
2)客户质量保证CQS
应用中介者/调停者模式后,不仅允许你对读写进行分离,而且可以对命令和查询进行有效处理,这也是引入MediatR的最大优势。
像我之前提到的,这个组件源于简单中介设计模式,其允许命令、查询和处理程序分离,并降低耦合。
3)上代码
你可以在github上面看到详细的代码,https://github.com/dmytrohridin/AspNetCoreMediatRSample, 但是我会对一些关键要点进行解释,以帮助大家如何应用MediatR组件。
*注:这些代码没有使用任何的分层,只是为什么展示组件用法。
Requests
当你开始使用MediatR组件,第一件事就是什么request,Request描述了你的命令和行为。
1 public class GetOrderQuery : IRequest<Order> 2 { 3 public GetOrderQuery(Guid id) 4 { 5 Id = id; 6 } 7 8 public Guid Id { get; } 9 }
GetOrderQuery描述了此方法的参数数Id,返回一个实体。所有的请求Request都要继承接口IRequest,这个接口相当于后续给handler处理时的契约。
Handlers
一旦request创建完成,你就可以创建处理程序handler。
1 public class GetOrderHandler : IRequestHandler<GetOrderQuery, Order> 2 { 3 private readonly IOrderRepository orderRepository; 4 5 public GetOrderHandler(IOrderRepository orderRepository) 6 { 7 this.orderRepository = orderRepository; 8 } 9 10 public Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken) 11 { 12 var result = orderRepository.Get(request.Id); 13 return Task.FromResult(result); 14 } 15 }
所有的Handers都要继承IRequestHandler接口,该接口有两个参数,第一个是输入,第二个是输出。更多的关于request和handlers的描述,在这里https://github.com/jbogard/MediatR/wiki。
现在,我们已经创建好了我们的Query和Handler,该如何使用呢?
1 public class OrdersController : ControllerBase 2 { 3 private readonly IMediator mediator; 4 5 public OrdersController(IMediator mediator) => 6 this.mediator = mediator; 7 8 [HttpGet("{id}")] 9 public async Task<Order> Get(Guid id) => 10 await mediator.Send(new GetOrderQuery(id)); 11 }
你要做的只是定义一个控制器,然后注入mediator,然后发送request,是不是So easy?
妈妈再也不用担心我的代码了。
最后
正如你所看见的,我们通过中介者模式和mediator组件,解耦了request和handlers,并且让controller变得更轻,同时根据符合CQS法则,很赞吧?
这个虽然称不上“银弹”,但是仍然很有用啊!