如何让在 ASP.Net Core 2.0 中编写的自定义异常处理程序在 ASP.Net Core 3.1 中工作?

问题描述 投票:1回答:1

通过Pluralsight的课程(.NET Logging Done Right: An Opinionated Approach Using Serilog by Erik Dahl),我开始在自己的ASP.Net Core 3.1 MVC项目中实现类似的解决方案。作为最初的概念验证,我从课程中下载了他的完整示例代码,并将他的日志记录器类库集成到我的项目中,看看它是否有效。

不幸的是,除了一个关键元素之外,一切似乎都能正常工作。在我的项目的Startup.cs文件的Configure方法中,没有使用 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)
                }));
        }
    }

我相信问题很可能在下面实际的CustomExceptionMiddleware.cs中的Invoke方法。

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课程上为其他试图这样做的人留下评论,以避免他们经历和我一样的挣扎。

c# asp.net-core-mvc serilog asp.net-core-3.1
1个回答
0
投票

你可以尝试在你的自定义异常处理中间件中重置端点和路由值,就像下面这样。

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.comdotnetaspnetcoreblob5e575a3e64254932c1fd4937041a4e7426afcde4srcMiddlewareDiagnosticssrcExceptionHandlerExceptionHandlerMiddleware.cs#L107。

© www.soinside.com 2019 - 2024. All rights reserved.