Как я могу заставить собственный обработчик исключений, написанный на ASP. Net Core 2.0, работать в ASP. Net Core 3.1? - PullRequest
1 голос
/ 25 мая 2020

Пройдя курс по Pluralsight (. NET Logging Done Right: Opinionated Approach Using Serilog by Erik Dahl), я начал реализовывать подобное решение в своем собственном проекте ASP. Net Core 3.1 MVC . В качестве первоначального доказательства концепции я загрузил его полный пример кода из курса и интегрировал его библиотеку классов логгера в свой проект, чтобы посмотреть, работает ли он.

К сожалению, вроде работает все, кроме одного критического элемента. В методе Configure файла Startup.cs моего проекта, а не app.UseExceptionHandler("/Home/Error");, у меня теперь есть app.UseCustomExceptionHandler("MyAppName", "Core MVC", "/Home/Error"); - теоретически это предназначено для использования некоторого настраиваемого промежуточного программного обеспечения, передачи некоторых дополнительных данных для регистрации ошибок, а затем вести себя как обычный обработчик исключений и попадете в путь обработки ошибок. На практике он не попадает в путь обработки ошибок, и пользователям отображается страница ошибок браузера.

В комментариях к коду промежуточного программного обеспечения указано, что этот код:

// based on Microsoft's standard exception middleware found here:
// https://github.com/aspnet/Diagnostics/tree/dev/src/
//         Microsoft.AspNetCore.Diagnostics/ExceptionHandler

Эта ссылка больше не работает. Я нашел новую ссылку, но она находится в архиве GitHub и не сказала мне ничего полезного.

Мне известно, что были изменения в способе работы маршрутизации между. Net Core 2.0 и 3.1, но я не уверен, вызовут ли они проблему, с которой я столкнулся. Я не думаю, что проблема в приведенном ниже коде, который вызывается из Startup.cs.

public static class CustomExceptionMiddlewareExtensions
    {
        public static IApplicationBuilder UseCustomExceptionHandler(
            this IApplicationBuilder builder, string product, string layer, 
            string errorHandlingPath)
        {
            return builder.UseMiddleware<CustomExceptionHandlerMiddleware>
                (product, layer, Options.Create(new ExceptionHandlerOptions
                {
                    ExceptionHandlingPath = new PathString(errorHandlingPath)
                }));
        }
    }

Я считаю, что проблема, скорее всего, в методе Invoke в фактическом CustomExceptionMiddleware.cs ниже:

public sealed class CustomExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ExceptionHandlerOptions _options;
        private readonly Func<object, Task> _clearCacheHeadersDelegate;
        private string _product, _layer;

        public CustomExceptionHandlerMiddleware(string product, string layer,
            RequestDelegate next,
            ILoggerFactory loggerFactory,
            IOptions<ExceptionHandlerOptions> options,
            DiagnosticSource diagSource)
        {
            _product = product;
            _layer = layer;

            _next = next;
            _options = options.Value;
            _clearCacheHeadersDelegate = ClearCacheHeaders;
            if (_options.ExceptionHandler == null)
            {
                _options.ExceptionHandler = _next;
            }
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                WebHelper.LogWebError(_product, _layer, ex, context);

                PathString originalPath = context.Request.Path;
                if (_options.ExceptionHandlingPath.HasValue)
                {
                    context.Request.Path = _options.ExceptionHandlingPath;
                }

                context.Response.Clear();
                var exceptionHandlerFeature = new ExceptionHandlerFeature()
                {
                    Error = ex,
                    Path = originalPath.Value,
                };

                context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
                context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
                context.Response.StatusCode = 500;
                context.Response.OnStarting(_clearCacheHeadersDelegate, context.Response);

                await _options.ExceptionHandler(context);

                return;
            }
        }

        private Task ClearCacheHeaders(object state)
        {
            var response = (HttpResponse)state;
            response.Headers[HeaderNames.CacheControl] = "no-cache";
            response.Headers[HeaderNames.Pragma] = "no-cache";
            response.Headers[HeaderNames.Expires] = "-1";
            response.Headers.Remove(HeaderNames.ETag);
            return Task.CompletedTask;
        }
    }

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

Ответы [ 2 ]

1 голос
/ 17 июля 2020

Я на самом деле рекомендую более простой подход, чем то, что я изначально показал в курсе. NET Logging Done Right (этот курс был построен на основе. NET Framework по большей части и ASP. NET Core модуль был добавлен после оригинальной публикации). Лучшим курсом для ведения журнала ASP. NET Core является более новый эффективный вход в ASP. NET Core. Но вместо того, чтобы просто отправить вас на другой курс для просмотра, позвольте мне ответить на ваш вопрос.

Я думаю, вам следует использовать промежуточное ПО UseExceptionHandler(string path). Вы можете записать исключение в код ошибки (код страницы контроллера или бритвы). Вы можете увидеть это конкретно в этом репозитории кода:

https://github.com/dahlsailrunner/aspnetcore-effective-logging

В частности, посмотрите эти файлы в проекте BookClub.UI:

  • Startup.cs (Configure метод)
  • Pages / Error.cs html
  • Pages / Error.cs html .cs

Это сведет ваш собственный код к минимуму (всегда хорошо).

HTH

0 голосов
/ 26 мая 2020

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

try
{
    context.Response.Clear();

    context.SetEndpoint(endpoint: null);
    var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
    routeValuesFeature?.RouteValues?.Clear();

    var exceptionHandlerFeature = new ExceptionHandlerFeature()
    {
        Error = ex,
        Path = originalPath.Value,
    };

//...

Для получения дополнительной информации, пожалуйста, проверьте исходный код ExceptionHandlerMiddleware в github:

https://github.com/dotnet/aspnetcore/blob/5e575a3e64254932c1fd4937041a4e7426afcde4/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs#L107

...