ASP.NET Core 使用 MediatR 實作消息通知

Posted on 2019-04-23

在之前的文章 ( ASP.NET Core 使用 MediatR 簡單的實現 Clean Architecture、CQRS 和分層架構 ) 已經有介紹基本的 MediatR 的用法了,現在要介紹的是它的消息通知功能

範例 Repository 在 Github

新增 Person 的通知 BusinessLogic

模擬新增 Person 之後要發 Mail 和送到 MQ

  • 建立 AddPersonNotification,實作 MediatR 的 INotification
public class AddPersonNotification : INotification
{
    public AddPersonNotification(Person person)
    {
        Id = person.Id;
        Name = person.Name;
    }

    public int Id { get; private set; }

    public string Name { get; private set; }
}
  • 建立 AddPersonMailNotificationHandler,來處理 AddPersonNotification,需要實作 MediatR 的 INotification,會需要實作一個 Handle 的方法,方法第一個參數就是實作 INotification 的類別 (泛型參數)
    • 泛型參數是實作 INotification 的 AddPersonNotification
    • 內容不是我們的重點,直接使用 Console.WriteLine 印出來,實際上請換成自己要執行的程式碼
public class AddPersonMailNotificationHandler : INotificationHandler<AddPersonNotification>
{
    public Task Handle(AddPersonNotification notification, CancellationToken cancellationToken)
    {
        Console.WriteLine("Mail Notification");
        return Task.CompletedTask;
    }
}
  • 建立 AddPersonMqNotificationHandler,方式和 AddPersonMailNotificationHandler 一樣
public class AddPersonMqNotificationHandler : INotificationHandler<AddPersonNotification>
{
    public Task Handle(AddPersonNotification notification, CancellationToken cancellationToken)
    {
        Console.WriteLine("Mq Notification");
        return Task.CompletedTask;
    }
}

修改新增 Person 的 CommandHandler BusinessLogic

  • constructor 注入 IMediator
  • 使用 Mediator 的 Publish 方法,把需要處理的物件丟進去 (也就是實作 INotification 的物件),因為沒有回傳值,就直接 await 它就好
public class AddPersonCommandHandler : IRequestHandler<AddPersonCommand, Unit>
{
    private readonly AppDbContext _dbContext;
    private readonly IMediator _mediator;

    public AddPersonCommandHandler(AppDbContext dbContext, IMediator mediator)
    {
        _dbContext = dbContext;
        _mediator = mediator;
    }

    public async Task<Unit> Handle(AddPersonCommand request, CancellationToken cancellationToken)
    {
        var person = new Person { Id = request.Id, Name = request.Name };
        await _dbContext.Person.AddAsync(person, cancellationToken);
        await _dbContext.SaveChangesAsync(cancellationToken);

        await _mediator.Publish(new AddPersonNotification(person), cancellationToken);

        return Unit.Value;
    }
}
  • 實際新增 Person 測試,可以看到有印出兩個 Notification

多個 Notification 的問題

預設處理 Notification 時,會等每一個處理的 Handler 都執行完成。如果這不是你想要的執行方式,可以參考官網的 MediatR.Examples.PublishStrategies 程式碼,修改自己的程式碼,達到下面這 6 種策略