MediatR 行为的约束违反异常
Posted
技术标签:
【中文标题】MediatR 行为的约束违反异常【英文标题】:Constraint Violated Exception on MediatR Behavior 【发布时间】:2019-02-04 10:02:04 【问题描述】:我将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>();
Mediator 发送的 GetPostsRequest 由 Handler 执行:
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'.
我错过了什么?
【问题讨论】:
请您展示一下您的调用方式 - 用什么?参数?我认为这是一个通用的不匹配 我认为这是一对多的通用包装器 -Envelope<TResponse>
!= Envelope<Response>
我不是在调用它...它正在被注入。请注意,在我使用泛型的行为上:TRequest 和 TResponse。
@Alex Envelopeservices.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
我不认为这条线能达到你预期的效果。
在您的示例中,您的请求类型是 IRequest<Envelope<Response>>
,因此当 MediatR 查找管道行为时,它将查找 IPipelineBehavior<Request, Envelope<Response>>
。
由于IPipelineBehavior<,>
的 DI 容器中有一个开放通用注册,因此将使用该实现。因此来自IPipelineBehavior<,>
的泛型类型参数将用于实例化ValidationBehavior<,>
的类型。
所以对于IPipelineBehavior<Request, Envelope<Response>>
,这将创建一个ValidationBehavior<Request, Envelope<Response>>
。这意味着在您的通用实现中,TRequest
将是 Request
,TResponse
将是 Envelope<Response>
。然而,这意味着您的类型上的类型约束意味着TRequest
,或在这种情况下为Request
,需要实现IRequest<Envelope<Envelope<Response>>>
。当然,事实并非如此,因此可以解释您所看到的类型约束违规。
不幸的是,这意味着您无法按照自己希望的方式进行操作。您不能对泛型类型施加类型约束,至少对 Envelope<T>
没有。
【讨论】:
这就是为什么最初我尝试使用 ValidationBehaviorErrors
属性的IEnvelope
接口,这样你就可以在你的行为中检查IEnvelope
类型,然后设置错误,而无需访问实际的响应类型。【参考方案2】:
您的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>
【讨论】:
我不能用那个。 Request 和 Response 类的具体例子。该行为必须使用泛型,仅指定 Response 的类型为 Envelope以上是关于MediatR 行为的约束违反异常的主要内容,如果未能解决你的问题,请参考以下文章