问题描述
我对ASP.NET核心项目使用Mediatr来处理所有请求。我实现了几个请求/响应/处理程序。它们中的每一个都可以抛出一个特定的异常,让我们将其称为MyException&Quot;类。 我将异常处理程序定义为
public class MyExceptionHandler : RequestExceptionHandler<MyRequest<MyResponse>, MyResponse, MyException>
{
protected override void Handle(MyRequest<MyResponse> request, MyException exception, RequestExceptionHandlerState<MyResponse> state)
{
MyResponse response = new MyResponse();
//Set some specific properties here in the response to indicate an error occurred
state.SetHandled(response);
}
}
我将这个异常处理程序添加到(Autofac)依赖项容器中,如果我在MyHandler中抛出MyRequest和MyResponse的MyException,就可以正常工作。然而,我有几十个请求、响应和相应的处理程序。那么,我如何为该特定异常的所有响应注册该异常处理程序(注意:所有响应都派生自同一个基类)。它尝试了类似下面的内容,但没有被调用。只有当我给出实际的类型时,它才能起作用,但这意味着我必须为每个类型创建一个异常处理程序,这是不实际的。有什么办法解决这个问题吗?
public class MyExceptionHandler : RequestExceptionHandler<IRequest<BaseResponse>, BaseResponse, MyException>
{
protected override void Handle(IRequest<BaseResponse> request, MyException exception, RequestExceptionHandlerState<BaseResponse> state)
{
BaseResponse response = new BaseResponse();
//Set some specific properties here in the response to indicate an error occurred
state.SetHandled(response);
}
}
推荐答案
AFAIK,处理程序旨在用于特定类型的请求、响应和异常。MediatR
在这种情况下无法执行泛型变量,因为发生异常时是not how they are being resolved。
因此,基本上,您所做的与您试图实现的目标非常接近。您可以创建一个通用抽象处理程序,并根据需要拥有任意数量的派生类型化实现,但您始终必须创建该样板。下面是捕获InvalidOperationException
的处理程序的示例。
public class BaseResponse
{
public bool Error { get; set; }
public string ErrorMessage { get; set; } = null!;
}
public class SomeResponse : BaseResponse {}
public class BaseRequest<TResponse> : IRequest<TResponse> where TResponse : BaseResponse {}
public class SomeRequest : BaseRequest<SomeResponse> {}
public class SomeRequestHandler : IRequestHandler<SomeRequest, SomeResponse>
{
public Task<SomeResponse> Handle(SomeRequest request, CancellationToken cancellationToken)
{
throw new InvalidOperationException();
}
}
public abstract class
AbstractInvalidOperationExceptionHandler<TRequest, TResponse> : RequestExceptionHandler<TRequest, TResponse, InvalidOperationException>
where TRequest : BaseRequest<TResponse>
where TResponse : BaseResponse, new()
{
protected override void Handle(TRequest request, InvalidOperationException exception, RequestExceptionHandlerState<TResponse> state)
{
var response = new TResponse
{
Error = true,
ErrorMessage = exception.Message
};
state.SetHandled(response);
}
}
public class SomeInvalidOperationExceptionHandler : AbstractInvalidOperationExceptionHandler<SomeRequest, SomeResponse>
{
}
这应该可以按预期工作,要求您为TRequest
+TResponse
的每个组合添加一个派生类型。如果不使用Autofac-PlugIn for MediatR,则还必须手动注册每个派生类型,Autofac-PlugIn for MediatR使用程序集扫描来注册RequestExceptionHandler<,,,>
的所有实现。
还有第二种选择,它类似于建议的中间件,但不是编写中间件,而是为接口的每个异常IExceptionFilter
(或者IAsyncExceptionFilter
如果这里需要async
)创建一个实现)。
如果再次处理InvalidOperationFilter
类型的异常,它将如下所示:
public class InvalidOperationExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception is not InvalidOperationException invalidOperationException)
{
return;
}
context.ExceptionHandled = true; // this follows the same principle as MediatR, you need to set it as handled, for the pipeline to stop executing!
// this will set the response to 409
context.Result = new ConflictObjectResult(new
{
Message = invalidOperationException.Message
});
}
}
现在可以很好地工作,该筛选器只需要注册一次,但这可能不是处理错误并将它们返回给客户端的理想方式。它还(紧密地)将您的异常处理逻辑耦合到框架。
这篇关于如何在Mediatr中为所有请求定义一个特定异常处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!