Обработка исключений Asp.Net Core Razor Pages нарушает работу приложения - PullRequest
0 голосов
/ 23 июня 2019

Я создаю приложение Asp.Net Core 2.2 Razor Pages. Я пишу глобальную обработку исключений, чтобы избежать попыток перехватить блоки во многих местах. Я следовал за статьей - Справочник по обработке исключений

Вот ссылка для демонстрационного решения

Вот мой код,

In Startup.cs

if(env.IsDevelopment())
{
    //app.UseDeveloperExceptionPage(new DeveloperExceptionPageOptions {
    //    SourceCodeLineCount = 2
    //});
    //app.UseDatabaseErrorPage();
    app.UseExceptionHandler("/Error");
    app.UseStatusCodePagesWithReExecute("/Error/{0}");
    app.UseExceptionMiddleware();
} else {...}

In ExceptionMiddleware.cs

public ExceptionMiddleware(RequestDelegate next,IMailService emailSender)
{
    _next = next;
    _emailSender = emailSender;
}

public async Task InvokeAsync(HttpContext context)
{
    try
    {
        await _next(context);
    } catch(Exception ex)
    {
        EmailException(context,ex);
    }
}

private async void EmailException(HttpContext context,Exception ex)
{
    var uaString = context.Request.Headers["User-Agent"].ToString();
    var ipAnonymizedString = context.Connection.RemoteIpAddress.AnonymizeIP();
    var userId = "Unknown";
    var profileId = "Unknown";
    if(context.User.Identity.IsAuthenticated)
    {
        userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
        profileId = context.User.GetUserClaim(ClaimsKey.ProfileId);
    }

    var sb = new StringBuilder($"An error has occurred on {context.Request.Host}. \r\n \r\n");
    sb.Append($"Path = {context.Request.Path} \r\n \r\n");
    sb.Append($"Error Message = {ex.Message} \r\n");
    sb.Append($"Error Source = {ex.Source} - {profileId} \r\n");

    if(ex.InnerException != null)
    {
        sb.Append($"Inner Exception = {ex.InnerException.ToString()} \r\n");
    } else
    {
        sb.Append("Inner Exception = null \r\n");
    }

    sb.Append($"Error StackTrace = {ex.StackTrace} \r\n");

    await _emailSender.SendMasterEmailAsync($"Error on {context.Request.Host}.",sb.ToString(),uaString,ipAnonymizedString,userId);

    throw ex;
}

Теперь я создаю исключение в одном из запросов на получение страницы, как показано ниже,

public void OnGet()
{
    throw new Exception();
}

Промежуточное программное обеспечение перехватывает исключение и выдает его после отправки электронной почты. Затем Visual Studio сообщает, что приложение находится в режиме прерывания, а Visual Studio останавливается. Но мой Error.cshtml.cs не захватывает исключение до того, как приложение сломается и остановится. Любая идея, где я иду не так?

1 Ответ

2 голосов
/ 23 июня 2019

В своем асинхронном руководстве GitHub-репозитории Дэвид Фаулер утверждает, что:

Использование асинхронного void в приложениях ASP.NET Core ВСЕГДА плохо.Избегайте этого, никогда не делайте этого.Как правило, он используется, когда разработчики пытаются реализовать шаблоны «огонь и забыть», запускаемые действием контроллера.Асинхронные методы void приводят к аварийному завершению процесса, если выбрасывается исключение.

Для описываемой ошибки последняя строка имеет решающее значение - ваше приложение выдает исключение, котороесбой процесса.

Для EmailException вам следует переключиться с использования async void на async Task, например:

public ExceptionMiddleware(RequestDelegate next,IMailService emailSender)
{
    ...
}

public async Task InvokeAsync(HttpContext context)
{
    try
    {
        await _next(context);
    }
    catch(Exception ex)
    {
        await EmailException(context, ex); // Await.
    }
}

private async Task EmailException(HttpContext context, Exception ex) // Return a Task.
{
    ...

    throw ex;
}

Если причина, по которой вы пытаетесьasync void используется для того, чтобы вам не приходилось ждать отправки электронного письма, прежде чем возвращать ответ пользователю. Возможно, вы захотите использовать Background Task для этого.

...