مدیریت ایونتها در MediatR
نویسنده: محمد شریفی
تاریخ: ۱۴۰۳/۰۹/۱۳ ۱۱:۳۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
INotification تعریف میشوند. Event به معنای اعلان (Notification) است که میتواند توسط یک یا چند هندلر پردازش شود.dotnet add package MediatR dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
INotification ارثبری میکند، به عنوان ایونت تعریف میکنیم:using MediatR;
public class OrderCreatedEvent : INotification
{
public int OrderId { get; set; }
public DateTime CreatedAt { get; set; }
public OrderCreatedEvent(int orderId, DateTime createdAt)
{
OrderId = orderId;
CreatedAt = createdAt;
}
}using MediatR;
public class LogOrderHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[1] Logging Order Created: {notification.OrderId}");
return Task.CompletedTask;
}
}
public class SendEmailHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[2] Sending Email for Order: {notification.OrderId}");
return Task.CompletedTask;
}
}
public class UpdateInventoryHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[3] Updating Inventory for Order: {notification.OrderId}");
return Task.CompletedTask;
}
}using MediatR;
public class OrderedNotificationHandler<TNotification> : INotificationHandler<TNotification>
where TNotification : INotification
{
private readonly IEnumerable<INotificationHandler<TNotification>> _handlers;
public OrderedNotificationHandler(IEnumerable<INotificationHandler<TNotification>> handlers)
{
_handlers = handlers;
}
public async Task Handle(TNotification notification, CancellationToken cancellationToken)
{
foreach (var handler in _handlers.OrderBy(h => GetPriority(h)))
{
await handler.Handle(notification, cancellationToken);
}
}
private int GetPriority(INotificationHandler<TNotification> handler)
{
var priorityAttribute = handler.GetType()
.GetCustomAttributes(typeof(HandlerPriorityAttribute), true)
.FirstOrDefault() as HandlerPriorityAttribute;
return priorityAttribute?.Priority ?? int.MaxValue;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class HandlerPriorityAttribute : Attribute
{
public int Priority { get; }
public HandlerPriorityAttribute(int priority) => Priority = priority;
}[HandlerPriority(1)]
public class LogOrderHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[1] Logging Order Created: {notification.OrderId}");
return Task.CompletedTask;
}
}
[HandlerPriority(2)]
public class SendEmailHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[2] Sending Email for Order: {notification.OrderId}");
return Task.CompletedTask;
}
}
[HandlerPriority(3)]
public class UpdateInventoryHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"[3] Updating Inventory for Order: {notification.OrderId}");
return Task.CompletedTask;
}
}using MediatR; var builder = WebApplication.CreateBuilder(args); builder.Services.AddMediatR(typeof(Program)); builder.Services.Decorate(typeof(INotificationHandler<>), typeof(OrderedNotificationHandler<>)); var app = builder.Build(); app.Run();
using MediatR;
public class OrderService
{
private readonly IMediator _mediator;
public OrderService(IMediator mediator)
{
_mediator = mediator;
}
public async Task CreateOrder(int orderId)
{
Console.WriteLine("Creating Order...");
var orderCreatedEvent = new OrderCreatedEvent(orderId, DateTime.UtcNow);
await _mediator.Publish(orderCreatedEvent);
}
}Creating Order... [1] Logging Order Created: 123 [2] Sending Email for Order: 123 [3] Updating Inventory for Order: 123
INotificationPublisherوجود دارد که نحوه فراخوانی هندلرها را کنترل میکند.ForeachAwaitPublisher است:public class ForeachAwaitPublisher : INotificationPublisher
{
public async Task Publish(
IEnumerable<NotificationHandlerExecutor> handlerExecutors,
INotification notification,
CancellationToken cancellationToken)
{
foreach (var handler in handlerExecutors)
{
await handler
.HandlerCallback(notification, cancellationToken)
.ConfigureAwait(false);
}
}
}TaskWhenAllPublisher نیز استفاده کرد:public class TaskWhenAllPublisher : INotificationPublisher
{
public Task Publish(
IEnumerable<NotificationHandlerExecutor> handlerExecutors,
INotification notification,
CancellationToken cancellationToken)
{
var tasks = handlerExecutors
.Select(handler => handler.HandlerCallback(
notification,
cancellationToken))
.ToArray();
return Task.WhenAll(tasks);
}
}ForeachAwaitPublisher:TaskWhenAllPublisher:TaskWhenAllPublisher را ذخیره کنید، میتوانید به Property Task.Exception دسترسی داشته باشید که شامل یک AggregateException است و میتوانید پیادهسازی برخورد بهتر با استثناءها را پیادهسازی کنید.INotificationPublisher، باید یک Action از نوع MediatRServiceConfiguration را ارائه دهید و MediatRServiceConfiguration را پیکربندی کنید.TaskWhenAllPublisher استفاده کنید، میتوانید:NotificationPublisher اختصاص دهید.NotificationPublisherType مشخص کنید:services.AddMediatR(config => {
config.RegisterServicesFromAssemblyContaining<Program>();
// Setting the publisher directly will make the instance a Singleton.
config.NotificationPublisher = new TaskWhenAllPublisher();
// Setting the publisher type will:
// 1. Override the value set on NotificationPublisher
// 2. Use the service lifetime from the ServiceLifetime property below
config.NotificationPublisherType = typeof(TaskWhenAllPublisher);
config.ServiceLifetime = ServiceLifetime.Transient;
});