MediatR行为违反约束的异常

时间:2018-08-29 14:50:07

标签: c# asp.net-core mediatr

我将MediatR用于以下课程:

public class GetPostsRequest : IRequest<Envelope<GetPostsResponse>> {
  public Int32 Age { get; set; }
}

public class GetPostResponse {
  public String Title { get; set; }
  public String Content { get; set; }      
}

其中信封是包装类:

public class Envelope<T> {
  public List<T> Result { get; private set; } = new List<T>();  
  public List<Error> Errors { get; private set; } = new List<Error>();
}

由中介者发送的GetPostsRequest由处理程序执行:

public class GetPostsRequestHandler : IRequestHandler<GetPostsRequest, Envelope<GetPostsResponse>> {

  public async Task<Envelope<GetPostsResponse>> Handle(GetPostsRequest request, CancellationToken cancellationToken) {
  }

}

MediatR允许使用行为,该行为在特定请求的处理程序之前执行。我创建了一个ValidationBehavior,如下所示:

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, Envelope<TResponse>> 
    where TRequest : IRequest<Envelope<TResponse>> {

  private readonly IEnumerable<IValidator<TRequest>> _validators;

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

  public Task<Envelope<TResponse>> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<Envelope<TResponse>> next) {

    ValidationContext context = new ValidationContext(request);

    List<Error> errors = _validators
      .Select(x => x.Validate(context))
      .SelectMany(x => x.Errors)
      .Select(x => new Error(ErrorCode.DataNotValid, x.ErrorMessage, x.PropertyName))
      .ToList();

    if (errors.Any())
      return Task.FromResult<Envelope<TResponse>>(new Envelope<TResponse>(errors));  

    return next();

  }

}

然后我在ASP.NET Core应用程序上注册了ValidationBehavior:

services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

当我调用API时,出现以下错误:

An unhandled exception has occurred while executing the request.
System.ArgumentException: GenericArguments[0], 'TRequest', on 'ValidationBehavior`2[TRequest,TResponse]' violates the constraint of type 'TRequest'. 
---> System.TypeLoadException: GenericArguments[0], 'TRequest', on 'ValidationBehavior`2[TRequest,TResponse]' violates the constraint of type parameter 'TRequest'.

我想念什么?

2 个答案:

答案 0 :(得分:1)

services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

我认为这行不符合您的预期。

在您的示例中,您的请求类型为IRequest<Envelope<Response>>,因此,在MediatR寻找管道行为时,它将寻找IPipelineBehavior<Request, Envelope<Response>>

由于DI容器中有IPipelineBehavior<,>的开放式注册,因此将使用该实现。因此,来自IPipelineBehavior<,>的泛型类型参数将用于实例化ValidationBehavior<,>的类型。

因此对于IPipelineBehavior<Request, Envelope<Response>>,这将创建一个ValidationBehavior<Request, Envelope<Response>>。这意味着在您的通用实现中,TRequest将是Request,而TResponse将是Envelope<Response>。但是,这意味着您类型上的类型约束意味着TRequest(在这种情况下为Request)需要实现IRequest<Envelope<Envelope<Response>>>。当然,事实并非如此,因此可以解释您所看到的违反类型约束的情况。

不幸的是,这意味着您无法按照您希望的方式进行操作。您不能对通用类型施加类型约束,对于Envelope<T>至少不能施加约束。

答案 1 :(得分:0)

您的ValidationBehavior指定TRequest必须是IRequest<Envelope<TResponse>>
您的请求实现了IRequest<Envelope<Response>> (不匹配-Envelope<TResponse>不是Envelope<Response>

但是,您的ValidationBehavior实现了IPipelineBehavior<TRequest, Envelope<TResponse>> 并具有约束where TRequest : IRequest<Envelope<TResponse>>

因此,将Envelope<TResponse>更改为Envelope<Response>