中介者模式实现与MediatR应用

概要

1. Console App Demo
2. Web API + MediatR Demo

Console App Demo

简单的Console App Demo,包括使用自建的中介者对象实现以及MediatR实现

Web API + MediatR Demo

在WebAPI中使用MediatR,最大的改变是将原本注入到controller的依赖分散到了MediatR消息的处理方法中

传统的依赖注入如下图
传统的依赖注入

使用MediatR后,MediatR作为抽象的一层将依赖进一步根据具体逻辑分散
使用MediatR的依赖注入

而接口则变得非常简洁,即
1.发送MediatR消息
2.获得结果
3.返回结果

在MediatR消息的处理方法中,当然也可以通过注入MediatR来再次发送消息,即嵌套的调用。最大程度得分离逻辑来降低逻辑上的耦合

...
using MediatR;
using Application.Exceptions;
using Application.Item.Models;
using Data.RepositoryInterfaces;
using Domain.BaseInterfaces;
using Domain.Entities;

namespace WebApp.Controllers
{

    [ApiController]
    public class ItemController : ControllerBase
    {

        private readonly IMediator _mediator;

        public ItemController(IMediator mediator)
        {
            _mediator = mediator;
        }

        [HttpGet]
        [Route("")]
        public async Task<ActionResult> Get(int itemId)
        {
            var result = await _mediator.Send(new GetItem(id, userid));
            if (result == null) return NotFound();
            return Ok(result);
        }
    }
}

namespace Application.Item.Queries
{
    public class GetItem : IRequest<ItemViewModel>
    {
        public GetItem(int itemId, string userId)
        {
            UserId = userId;
            ItemId = itemId;
        }

        public string UserId { get; }
        public int ItemId { get; }
    }

    public class GetItemHandler : IRequestHandler<GetItem, ItemViewModel>
    {
        private readonly IMediator _mediator;
        private readonly IItemRepository _itemRepository;

        public GetItemHandler(
            IMediator mediator,
            IItemRepository itemRepository
        )
        {
            _mediator = mediator;
            _itemRepository = itemRepository;
        }

        public async Task<ItemViewModel> Handle(GetItem arg, CancellationToken cancellationToken)
        {
            var item = await _itemRepository.Get()
                .Where(i => i.Id == arg.ItemId)
                .Select(i => new
                {
                    Id = i.Id,
                    Name = i.Name,
                }).SingleOrDefaultAsync();

            if (item == null)
                throw new NotFoundException(arg.ItemId.ToString(), nameof(Domain.Entities.Item));

            var companyUser = await _mediator.Send(new GetCompanyUser(arg.UserId, item.CompanyId));

            bool isCompanyUser = companyUser != null;

            return new ItemViewModel(){
                ItemId = item.Id,
                ItemName = item.Name,
                IsCompanyUser = isCompanyUser
            };
        }
    }

    public class GetItemPreProcessor : IRequestPreProcessor<GetItem>
    {
        private readonly IMediator _mediator;
        public GetItemPreProcessor(
            IMediator mediator)
        {
            _mediator = mediator;
        }

        public Task<ItemViewModel>  Process(GetItem request, CancellationToken cancellationToken)
        {
            return await _mediator.Send(new InsertItemViewRecord(request));
        }
    }
}


namespace Application.Item.Commands
{
    //implement InsertItemViewRecord
}

Demo主要流程如下图