本文介绍了如何在Mediatr中为所有请求定义一个特定异常处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对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中为所有请求定义一个特定异常处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-15 17:51