33

我正在使用 ASP.NET Core、内置容器和支持“行为”管道的 MediatR 3 :

public class MyRequest : IRequest<string>
{
    // ...
}

public class MyRequestHandler : IRequestHandler<MyRequest, string>
{
    public string Handle(MyRequest message)
    {
        return "Hello!";
    }
}

public class MyPipeline<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
    {
        var response = await next();
        return response;
    }
}

// in `Startup.ConfigureServices()`:
services.AddTransient(typeof(IPipelineBehavior<MyRequest,str‌​ing>), typeof(MyPipeline<MyRequest,string>))

我在管道中需要一个 FluentValidation 验证器。在 MediatR 2 中,创建了一个验证管道

public class ValidationPipeline<TRequest, TResponse>
    : IRequestHandler<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{

    public ValidationPipeline(IRequestHandler<TRequest, TResponse> inner, IEnumerable<IValidator<TRequest>> validators)
    {
        _inner = inner;
        _validators = validators;
    }

    public TResponse Handle(TRequest message)
    {
        var failures = _validators
            .Select(v => v.Validate(message))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();
        if (failures.Any())
            throw new ValidationException(failures);
        return _inner.Handle(request);
    }

}

我现在如何为新版本做到这一点?如何设置要使用的验证器?

4

3 回答 3

30

过程完全相同,您只需更改界面即可使用新IPipelineBehavior<TRequest, TResponse>界面。

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
    {
        var context = new ValidationContext(request);
        var failures = _validators
            .Select(v => v.Validate(context))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        if (failures.Count != 0)
        {
            throw new ValidationException(failures);
        }

        return next();
    }
}

对于验证器,您应该将所有验证器注册为IValidator<TRequest>内置容器,以便将它们注入行为中。如果你不想一一注册,我建议你看看很棒的Scrutor 库,它带来了汇编扫描功能。这样它会自己找到你的验证器。

此外,在新系统中,您不再使用装饰器模式,您只需在容器中注册您的通用行为,MediatR 就会自动获取它。它可能看起来像:

var services = new ServiceCollection();
services.AddMediatR(typeof(Program));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
var provider = services.BuildServiceProvider();
于 2017-02-17T03:49:25.133 回答
8

我已将 .net 核心集成打包到 nuget 中,请随意使用: https ://www.nuget.org/packages/MediatR.Extensions.FluentValidation.AspNetCore

只需在配置部分插入:

services.AddFluentValidation(new[] {typeof(GenerateInvoiceHandler).GetTypeInfo().Assembly});

GitHub

于 2019-09-11T14:48:39.643 回答
1

On the new version (MediatR (>= 9.0.0)) you can do something like this:

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        var context = new ValidationContext<TRequest>(request);
        var failures = _validators
            .Select(v => v.Validate(context))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        if (failures.Count != 0)
        {
            throw new ValidationException(failures);
        }

        return next();
    }
}

Remember to add var context = new ValidationContext<TRequest>(request); in previous version like FluentApi 8.0 or below it used something like this var context = new ValidationContext(request);

for Register in Asp.Net Core in under IServiceCollection wright below code:

services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

Hope that's helpful!

于 2021-05-11T00:29:41.840 回答