有没有执行所有已注册接口实现的模式?

我在asp.net核心应用程序中有一个异常处理中间件,该中间件使用下面的IExceptionHandler来处理异常

public interface IExceptionHandler<T> where T:Exception
{
    ProblemDetails HandleException(T exception);
}

我想注册各种异常处理程序,例如

// Handles Sql based exceptions
public class SqlExceptionHandler: IExceptionHandler<SqlException>
{
    public ProblemDetails Handle(SqlException exception);
}

// Handles File based exceptions 
public class IOExceptionHandler : IExceptionHandler<IOException>
{
    public ProblemDetails Handle(IOException exception);
}

// Handles all the exceptions that are not handled by any handlers
public class ExceptionHandler : IExceptionHandler<Exception>
{
    public ProblemDetails Handle(Exception exception)
}

当触发异常中间件时,我希望根据类型自动触发异常处理程序,如果这些异常中的任何一个未处理异常,则希望让ExceptionHandler处理该异常。

是否可以根据类型自动触发异常处理程序实例? 另外,我希望这个IExceptionHandler是可扩展的,以便将来如果我想处理任何其他类型的Exception,我只需注册实现

huangyu0047 回答:有没有执行所有已注册接口实现的模式?

这个人花了我一段时间才能弄清楚,但它既有趣又充满挑战,并最终找到了可行的解决方案。

另外,我确实知道这可能不是您想要的。如果ASP提供了一些您可以在Startup类中注册的现成的东西,那会很好,我认为这是您正在寻找的东西

如果外面有人知道这种功能,我希望有更好的解决方案!

这是我使用过的[TestMethod],可以放在MSTest [TestClass]

[TestMethod]
public void _58790281()
{
    try
    {
        throw new IOException("Text IO Exception");
    }
    catch (Exception e)
    {
        PassExceptionToHandler(e);
    }
}

private void PassExceptionToHandler(Exception ex)
{
    Assembly assembly = Assembly.GetAssembly(typeof(IExceptionHandler<>));
    List<Type> concreteTypes = assembly.GetTypes().Where(a => !a.IsInterface).ToList();
    Type currentExceptionHandlerType = concreteTypes
        .FirstOrDefault(a => a.GetInterfaces().Any(i =>
            i.IsGenericType
            && i.GetGenericTypeDefinition() == typeof(IExceptionHandler<>)
            && i.GenericTypeArguments.Any(ii => ii == ex.GetType())));

    MethodInfo exceptionHandlerMethod = currentExceptionHandlerType.GetMethod("HandleException");

    var exceptionHanderInstance = Activator.CreateInstance(currentExceptionHandlerType);
    exceptionHandlerMethod.Invoke(exceptionHanderInstance,new object[] { ex });
}

编辑:当然,您将需要隔离处理程序,以减少反射成本,也许将它们放置在自己的程序集中,或对其进行修改以从命名空间或其他内容中获取类型,以使它不会查看您的所有类型。主装配体。

EDIT_01:ASP.Net Core实际上确实提供了一些用于全局异常处理的配置,只是遇到了https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-3.0

,

您可以使用Scrutor库来扫描任何接口的所有实现的程序集,并在该库的帮助下自动注册它们。 例如:

services.Scan(scan => scan
  .FromCallingAssembly()
    .AddClasses(x=> x.AssignableTo(typeof(IOpenGeneric<>))) // Can close generic types
      .AsImplementedInterfaces()
      .WithScopedLifetime()
);

然后,您可以在中间件内部调用IServiceProvider以获取所有已注册的实现,然后需要进行一些反射或动态调度才能执行所需异常处理程序的Handle方法。 此外,您还必须以某种方式保留该异常处理程序的顺序。让我解释一下我的意思。例如,对于SqlException,您必须执行SqlExceptionHandler(更具体),而不是ExceptionHandler。您将如何找出哪个处理程序更具体?

所有这些当然可以完成。但是,我认为这会 引入不必要的复杂性 给您的代码库。

我认为最好创建一个基本异常Middleware。 然后是多个派生的中间件。正如msdn中所述,好事是:

  

在中间件组件中添加中间件组件的顺序   Startup.Configure方法定义中间件的顺序   组件是根据请求调用的。

如您所见,采用这种方法,订单问题将自动得到解决。

以下是一些示例代码:

 public abstract class BaseExceptionHandlingMiddleware
    {
        private readonly RequestDelegate _nextMiddlewareRequestDelegate;

        public ExceptionHandlingMiddleware(RequestDelegate nextMiddlewareRequestDelegate)
        {
            _nextMiddlewareRequestDelegate = nextMiddlewareRequestDelegate;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _nextMiddlewareRequestDelegate(context);
            }
            catch (Exception exception)
            {
                await HandleExceptionAsync(context,exception);
            }
        }

        private static Task HandleExceptionAsync(HttpContext context,Exception exception)
        {
            var errorDescription = exception.Message;
            var result = JsonConvert.SerializeObject(new { error = errorDescription });

            context.Response.ContentType = MediaTypeNames.Application.Json;
            context.Response.StatusCode = (int)DetermineStatusCode(exception);
            return context.Response.WriteAsync(result);
        }

        protected virtual HttpStatusCode DetermineStatusCode(Exception exception);
    }

创建SqlExceptionHandlinMiddlewareIOExceptionHandlinMiddlewareGeneralExceptionHandlinMiddleware,然后覆盖DetermineStatusCode

然后注册它们:

builder.UseMiddleware<SqlExceptionHandlinMiddleware>();
builder.UseMiddleware<IOExceptionHandlinMiddleware>();
builder.UseMiddleware<GeneralExceptionHandlinMiddleware>();
本文链接:https://www.f2er.com/3128635.html

大家都在问