Нарушенное ограничение на поведение MediatR - PullRequest
0 голосов
/ 29 августа 2018

Я использую 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; }      
}

Где Envelope - это класс-оболочка:

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();

  }

}

И я зарегистрировал поведение ValidationBehavior в приложении ASP.NET Core:

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 голосов
/ 29 августа 2018
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>. Это, однако, означает, что тип containt в вашем типе означает, что TRequest, или Request в этом случае, необходимо реализовать IRequest<Envelope<Envelope<Response>>>. Конечно, это не тот случай, и поэтому он объясняет нарушение ограничения типа, которое вы видите.

К сожалению, это означает, что вы не можете сделать это так, как вы хотите, чтобы это работало. Вы не можете наложить ограничение на тип вашего общего типа, по крайней мере, на Envelope<T>.

0 голосов
/ 29 августа 2018

Ваш 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>

...