zoukankan      html  css  js  c++  java
  • [译]MediatR, FluentValidation, and Ninject using Decorators

    原文

    CQRS

    我是CQRS模式的粉丝。对我来说CQRS能让我有更优雅的实现。它同样也有一些缺点:通常需要更多的类,workflow不总是清晰的。

    MediatR

    MediatR的文档非常不错,在这就不重复了。但是为了有个基本的了解,在这还是举个小例子,来看看command是怎么被处理的:

    [Test]
    public void ItShouldHandleBasicCommands()
    {
        var mediator = GetMediator();
    
        var command = new Command();
        var response = mediator.Send(command);
    
        response.Should().NotBeNull();
    }
    

    MediatR接收一个command,让后将它发送到适当的handler去:

    public class Command : IRequest<Response>
    {
    }
    
    public class CommandHandler : IRequestHandler<Command, Response>
    {
        public Response Handle(Command message)
        {
            return new Response();
        }
    }
    

    注册command和command handler非常简单。下面的例子是关于使用Ninject基于约定来注册。找到所有的handler接口,绑定它们:

    kernel.Bind(scan => scan.FromThisAssembly()
        .SelectAllClasses()
        .Where(o => o.IsAssignableFrom(typeof(IRequestHandler<,>)))
        .BindAllInterfaces());
    

    下面是一些其他的注册,它们也非常重要。注册IMediator。factory实例的调用告诉MediatR如何解析单个和多个实例。然后注册MediatR。

    kernel.Bind<SingleInstanceFactory>()
        .ToMethod(context => (type => context.Kernel.Get(type)));
    kernel.Bind<MultiInstanceFactory>()
        .ToMethod(context => (type => context.Kernel.GetAll(type)));
    var mediator = kernel.Get<IMediator>();
    

    Validation and Decorators

    装饰模式可以让我们在不修改对象的前提下,增加这个对象的行为。一个通常的做法是添加输入验证。使用装饰器包装一个command handler,以使得可以在使用前验证这个command。下面的command和command handler简单的返回一个response。

    public class Foo : IRequest<Response>
    {
        public string Message { get; set; }
    }
    
    public class FooHandler : IRequestHandler<Foo, Response>
    {
        public Response Handle(Foo message)
        {
            return new Response();
        }
    }
    

    FluentValidation是个非常不错的验证包。首先我们需要一个validation类,然后我们需要用Ninject注册它。

    下面是一个简单的验证器。判断Message属性是否为空。如果为空,返回一个错误:

    public class FooValidator : AbstractValidator<Foo>
    {
        public FooValidator()
        {
            RuleFor(ping => ping.Message).NotEmpty();
        }
    }
    

    使用Ninject注册验证器非常简单。下面的代码绑定了程序集中所有的验证器:

    kernel.Bind(scan => scan.FromThisAssembly()
        .SelectAllClasses()
        .InheritedFrom(typeof(AbstractValidator<>))
        .BindAllInterfaces());
    

    下一步是使用这个validator。下面的代码来自Jimmy Bogard的网站。是一个实现用来在命令发送到handler前验证命令的装饰类的例子:

    public class ValidatingHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
        where TRequest : IRequest<TResponse>
    {
        private readonly IRequestHandler<TRequest, TResponse> handler;
        private readonly IValidator<TRequest> validator;
    
        public ValidatingHandler(IRequestHandler<TRequest, TResponse> handler, IValidator<TRequest> validator)
        {
            this.handler = handler;
            this.validator = validator;
        }
    
        [DebuggerStepThrough]
        public TResponse Handle(TRequest message)
        {
            var validationResult = validator.Validate(message);
    
            if (validationResult.IsValid)
                return handler.Handle(message);
    
            throw new ValidationException(validationResult.Errors);
        }
    }
    

    下一步是如何配置Ninjec来创建一个handler和装饰它。Binding Decorators - Mediators with Ninject这篇文章讲的非常好。"注册handler。当验证handler创建后,注入一个handler。当handler被请求返回一个validating handler。"

    当Ninject被要求创建一个handler,它首先创建一个calidating handler。

    kernel.Bind(scan => scan.FromThisAssembly()
        .SelectAllClasses()
        .Where(o => o.IsAssignableFrom(typeof(IRequestHandler<,>)))
        .BindAllInterfaces());
    
    kernel.Bind(scan => scan.FromThisAssembly()
        .SelectAllClasses()
        .InheritedFrom(typeof(IRequestHandler<,>))
        .BindAllInterfaces()
        .Configure(o => o.WhenInjectedInto(typeof(ValidatingHandler<,>))));
    
    kernel.Bind(typeof(IRequestHandler<,>)).To(typeof(ValidatingHandler<,>));
    

    下面看看如果command的message是空和不是空的时候是什么样子的。

    [Test]
    public void ItShouldProcessCommands()
    {
        var mediator = GetMediator();
    
        var command = new Foo { Message = "valid ping" };
        var response = mediator.Send(command);
    
        response.Should().NotBeNull();
    }
    
    [Test]
    public void ItShouldValidateTheCommand()
    {
        var mediator = GetMediator();
    
        var ping = new Foo();
        Action act = () => mediator.Send(ping);
    
        act.ShouldThrow<ValidationException>();
    }
    

    本文的源码位于github

  • 相关阅读:
    LeetCode24-Swap_Pairs
    LeeCode
    LeetCode3-Longest_Substring_Without_Repeating_Characters
    治愈 JavaScript 疲态的学习计划【转载】
    前端冷知识集锦[转载]
    知道这20个正则表达式,能让你少写1,000行代码[转载]
    关于简历和面试【整理自知乎】
    正念冥想方法
    一些职场经验【转载自知乎】
    犹太复国计划向世界展现了一个不一样的民族——观《犹太复国血泪史》有感
  • 原文地址:https://www.cnblogs.com/irocker/p/mediatr-fluentvalidation-and-ninject.html
Copyright © 2011-2022 走看看