• 初学者浅度剖析eShopOnContainers 里面用到的MediatR .


    一.介绍

       简单了解下开源项目 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();
            }
        }
  • 相关阅读:
    vue前端使用JsonViewer进行json展示
    vue代理服务器proxy配置
    'vue-cli-service' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
    Python中的高阶函数和内置高阶函数(abs,map,reduce,sorted,filter)
    Ant Design Vue 通过v-decorator实现数据绑定
    Vue脚手架(vue-cli)搭建和目录结构详解
    如何使用Postman从XML提取变量
    【已解决】Vue格式化js自动加上冒号和分号
    vue.js安装与搭建
    Python函数中如何返回多个值?
  • 原文地址:https://www.cnblogs.com/guoyiwen/p/10484468.html
Copyright © 2020-2023  润新知