使用 SimpleInjector 在 IExceptionFilter 中注入 Logger

Inject Logger in IExceptionFilter with SimpleInjector

我在 ASP.NET Core 2.1 WebAPI 应用程序中使用 Simple Injector。我有一个 IExceptionFilter,我想在其中记录错误。我的代码在下面(有效),但这是正确的方法吗?看起来工作量很大

public class HttpGlobalExceptionFilter : IExceptionFilter
{
    private readonly ILogger logger;

    public HttpGlobalExceptionFilter(Infrastructure.Common.ILogger logger)
    {
        // This is my own logger, implemented along the lines as mentioned here:
        // 
        this.logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        // Irrelevant stuff
        // ...

        var error = $"An error occured: {context.Exception.Message}";
        this.logger.LogError(error);
        context.ExceptionHandled = true;
    }
}

在我的 Startup.cs ConfigureServices() 中,我有:

services.AddMvc(options =>
{
    options.Filters.Add(new SimpleInjectorExceptionFilterDispatcher(
        this.container.GetInstance<IExceptionFilter>));
    // ...
});

而不是

services.AddMvc(options =>
{
    options.Filters.Add<HttpGlobalExceptionFilter>();
    // ...
});

在我的绑定中:

container.Register<IExceptionFilter, HttpGlobalExceptionFilter>();

最后,调度员:

public sealed class SimpleInjectorExceptionFilterDispatcher : IExceptionFilter
{
    private readonly Func<IExceptionFilter> exceptionFilterFunc;

    public SimpleInjectorExceptionFilterDispatcher(
        Func<IExceptionFilter> exceptionFilterFunc)
    {
        this.exceptionFilterFunc = exceptionFilterFunc;
    }

    public void OnException(ExceptionContext context)
    {
        this.exceptionFilterFunc.Invoke().OnException(context);
    }
}

这是让 Simple Injector 与 ASP.NET 的不同组件一起工作的方法吗?这是一个复杂的设置,我希望有一些更简单的东西,以便所有开发人员都能轻松理解代码。

此外,我能否完全避免 Microsoft DI 并使用 Simple Injector(并期望更简单的配置?)

参考文献:

如果 HttpGlobalExceptionFilter 的依赖项(目前 ILogger)是单例,您可以通过删除 SimpleInjectorExceptionFilterDispatcher 来简化您的解决方案。这会将解决方案简化为以下内容:

options.Filters.Add(new HttpGlobalExceptionFilter(new LoggerAdapter()));

这将手动构建过滤器及其依赖项。您也可以从容器中解析它。为确保您不会意外创建 Captive Dependencies,您应确保将 HttpGlobalExceptionFilter 注册为 Singleton:

container.RegisterSingleton<HttpGlobalExceptionFilter>();

services.AddMvc(options =>
{
    options.Filters.Add(this.container.GetInstance<HttpGlobalExceptionFilter>());
});

除了使用 MVC 过滤器之外,您还可以更上一层楼并定义一个中间件组件并将其连接起来,如 Simple Injector 文档中 here 所述。这进一步简化了注册,尽管它可能会使您的实施复杂化,具体取决于您的具体需要。

这意味着将您的 HttpGlobalExceptionFilter 重写为中间件组件。这可能如下所示:

public sealed class HttpGlobalExceptionMiddleware
    : Microsoft.AspNetCore.Http.IMiddleware
{
    private readonly Infrastructure.Common.ILogger logger;

    public HttpGlobalExceptionMiddleware(ILogger logger) =>
        this.logger = logger;

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            var error = $"An error occured: {ex.Message}";
            this.logger.LogError(error);            
            throw;
        }
    }
}

使用Simple Injector的UseMiddleware扩展方法,可以注册Simple Injector,同时添加到ASP.NETCore的中间件管道中:

app.UseMiddleware<HttpGlobalExceptionMiddleware>(container);