Исключения, выданные промежуточным программным обеспечением, не регистрируются (.UseExceptionHandler?) - PullRequest
0 голосов
/ 27 июня 2019

Черт возьми, я не могу понять это.

У меня есть какое-то промежуточное ПО, которое выбрасывает исключения, например

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
        ...
    }
}

Стандартное значение mw.Но когда исключение возникает в части 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()'.'

Eeek!Таким образом, он не будет работать волшебным образом из коробки, хотя в документации сказано:

Добавляет промежуточное программное обеспечение в конвейер, который будет перехватывать исключения, регистрировать их и повторно выполнятьзапрос в альтернативном конвейере.

Я хочу отметить, что до тех пор, пока класс контроллера украшен [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.Тип является интерфейсом или абстрактным классом и не может быть создан.Путь 'Критерии [0] .FieldName', строка 1, позиция 63. '

Ошибка в моем коде была легко обнаружена, как только я смог прочитать это, но в процессе работы мой WebApi не регистрировалэта информация.Все, что я вижу, это то, что был плохой запрос, и все, никакой дополнительной информации.

...