一.介绍
简单了解下开源项目 MedatR, eShopOnContainers, MediatR作者Jimmy Bogard :
Simple mediator implementation in .NET In-process messaging with no dependencies. Supports request/response, commands, queries, notifications and events, synchronous and async with intelligent dispatching via C# generic variance.
.NET中的简单中介实现 进程内没有依赖关系消息传递。支持以同步或异步的形式进行请求/响应,命令,查询,通知和事件的消息传递,并通过C#泛型支持消息的智能调度。
MediatR实现Pipeline ,通过Autofac 注入Log,FluentValidation ,来实现管道里记录日志,管道里验证实体数据.
二.MediatR的使用
1.安装NuGet包:
Install-Package MediatR.Extensions.Microsoft.DependencyInjectionFixed
Install-Package Autofac.Extensions.DependencyInjection
2.修改Startup.cs文件
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); var container = new ContainerBuilder(); container.Populate(services); container.RegisterModule(new MediatorModule()); return new AutofacServiceProvider(container.Build()); }
3.添加MediatorModule.cs文件
添加 builder.RegisterGeneric(typeof(xxx<,>)).As(typeof(IPipelineBehavior<,>)); 按你添加的顺序执行管道
public class MediatorModule : Autofac.Module { protected override void Load(ContainerBuilder builder) { builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly) .AsImplementedInterfaces(); // Register all the Command classes (they implement IRequestHandler) in assembly holding the Commands builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly) .AsClosedTypesOf(typeof(IRequestHandler<,>)); // Register the DomainEventHandler classes (they implement INotificationHandler<>) in assembly holding the Domain Events // builder.RegisterAssemblyTypes(typeof(ValuesController.Pings).GetTypeInfo().Assembly) // .AsClosedTypesOf(typeof(INotificationHandler<>)); // Register the Command's Validators (Validators based on FluentValidation library) builder .RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly) .Where(t => t.IsClosedTypeOf(typeof(IValidator<>))) .AsImplementedInterfaces(); builder.Register<ServiceFactory>(context => { var componentContext = context.Resolve<IComponentContext>(); return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; }; }); builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>)); builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>)); // builder.RegisterGeneric(typeof(TransactionBehaviour<,>)).As(typeof(IPipelineBehavior<,>)); } }
4.添加LoggingBehavior.cs文件
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger; public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger) => _logger = logger; public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { _logger.LogInformation("----- Handling command {CommandName} ({@Command})", request.GetGenericTypeName(), request); var response = await next(); _logger.LogInformation("----- Command {CommandName} handled - response: {@Response}", request.GetGenericTypeName(), response); return response; } }
5.添加ValidatorBehavior.cs文件
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger; private readonly IValidator<TRequest>[] _validators; public ValidatorBehavior(IValidator<TRequest>[] validators, ILogger<ValidatorBehavior<TRequest, TResponse>> logger) { _validators = validators; _logger = logger; } public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { var typeName = request.GetGenericTypeName(); _logger.LogInformation("----- Validating command {CommandType}", typeName); var failures = _validators .Select(v => v.Validate(request)) .SelectMany(result => result.Errors) .Where(error => error != null) .ToList(); if (failures.Any()) { _logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures); throw new OrderingDomainException( $"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures)); } return await next(); } }
6.添加CreateOrderCommandValidator.cs
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand> { public CreateOrderCommandValidator() { RuleFor(command => command.City).NotEmpty(); RuleFor(command => command.Street).NotEmpty(); RuleFor(command => command.State).NotEmpty(); RuleFor(command => command.Country).NotEmpty(); RuleFor(command => command.ZipCode).NotEmpty(); RuleFor(command => command.CardNumber).NotEmpty().Length(12, 19); RuleFor(command => command.CardHolderName).NotEmpty(); RuleFor(command => command.CardExpiration).NotEmpty().Must(BeValidExpirationDate).WithMessage("Please specify a valid card expiration date"); RuleFor(command => command.CardSecurityNumber).NotEmpty().Length(3); RuleFor(command => command.CardTypeId).NotEmpty(); RuleFor(command => command.OrderItems).Must(ContainOrderItems).WithMessage("No order items found"); } private bool BeValidExpirationDate(DateTime dateTime) { return dateTime >= DateTime.UtcNow; } private bool ContainOrderItems(IEnumerable<CreateOrderCommand.OrderItemDTO> orderItems) { return orderItems.Any(); } }