中间件引发的异常不会被记录(.UseExceptionHandler?)

时间:2019-06-27 12:21:47

标签: c# asp.net-core .net-core asp.net-core-2.2 kestrel-http-server

对我而言,我无法弄清楚。

我有一些中间件抛出异常,即

public class SubscriptionMiddleware
{
    private readonly RequestDelegate _next;
    ...

    public SubscriptionMiddleware(RequestDelegate next, ...)
    {
        _next = next;
        ...
    }

    public async Task Invoke(HttpContext context, ...)
    {           
        await _next(context); // Exception may occur here
        ...
    }
}

标准分子量。但是当await _next()部分发生异常时,它永远不会记录在任何地方...

我的控制器如下:

[ApiController]
[Authorize]
[Route("api/[controller]")]
public class SubscriptionsController : Controller
{
    [MiddlewareFilter(typeof(SubscriptionMiddlewareFilter))]
    [HttpPost("test")]
    public async Task<IActionResult> TestMethod(...)
    {
        ...
        return Ok(jsonResult);
    }
}

您可能已经注意到的中间件过滤器看起来像这样(如果有所不同):

public class SubscriptionMiddlewareFilter
{
    public void Configure(IApplicationBuilder app) => app.UseMiddleware<SubscriptionMiddleware>();
}   

所有在控制器方法中发生的异常都被记录下来,并且代码500自动返回。但是,返回400(错误请求)的异常(即某些JSON格式问题)都被吞没了...从未在任何地方记录过。我对它的印象是ApiController-s应该可以自动运行。

Program.cs代码也很标准:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(LogLevel.Trace);
        })
        .UseNLog()
        .ConfigureAppConfiguration(config =>
        {
            ...
        })
        .SuppressStatusMessages(true)
        .UseKestrel(opts =>
        {
            ...
        })              
        .UseStartup<Startup>();

我尝试使用的是UseExceptionHandler,但我认为使用的不正确。我在网上能找到的所有解决方案都可以将异常详细信息打印到一些HTML页面或JSON输出中-我只需要将它们记录下来,什么都不需要。

这是我的最新尝试,不过该代理从未被调用:

var exHandlerOpts = new ExceptionHandlerOptions
{
    ExceptionHandler = ctx =>
    {

        var ex = ctx.Features.Get<IExceptionHandlerFeature>().Error;

        ... log? ...

        return Task.CompletedTask;
    }
};

app
    .UseExceptionHandler(exHandlerOpts)
    .UseHsts()
    .UseHttpsRedirection()
    .UseAuthentication()
    .UseMvc()
    ...

我对此感到困惑,因为整个Asp.Net Core中的异常日志记录看起来非常优雅并且几乎是自动的,我的后台服务,范围服务,控制器等都很好地记录了它们。但是,错误的请求异常...在服务器端甚至都没有被提及?

仅放置.UseExceptionHandler()会抛出一个异常:

'An error occurred when configuring the exception handler middleware. Either the 'ExceptionHandlingPath' or the 'ExceptionHandler' option must be set in 'UseExceptionHandler()'.'

拜托!因此,尽管文档说:

  

在管道中添加一个可以捕获异常的中间件,记录它们,然后在备用管道中重新执行请求。

我想指出的是,只要控制器类用[ApiController]装饰,控制器使用的中间件中的所有异常都会被捕获而不被重发,例如

public async Task Invoke(HttpContext context, SubscriptionRequestData data)
{
    try
    {
        await _next(context);
    }
    catch (Exception ex)
    {
        // this will never happen
    }
}

我注意到无论我叫.UseExceptionHandler还是.UseExceptionMiddleware,情况都是如此。因此,捕获异常并检查异常的唯一方法是在调试器中(配置了异常设置)。

在我的特定情况下,错误的请求是由JSON格式异常引起的,我希望将其记录在某处。像这样:

  

Newtonsoft.Json.JsonSerializationException:'无法创建类型为PushService.Abstractions.Subscription.ICriterion的实例。类型是接口或抽象类,无法实例化。路径'Criteria [0] .FieldName',第1行,位置63。'

一旦我能够阅读此代码,便很容易发现该错误,但在生产中,我的WebApi不会记录此信息。我只会看到有一个错误的请求,仅此而已,没有更多信息。

0 个答案:

没有答案