繁体   English   中英

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

[英]How can I get a custom exception handler written in ASP.Net Core 2.0 to work in ASP.Net Core 3.1?

在完成 Pluralsight 课程(正确完成 .NET 日志记录:Erik Dahl 的使用 Serilog 的一种自以为是的方法)后,我开始在我自己的 ASP.Net Core 3.1 MVC 项目中实施类似的解决方案。 作为概念的初步证明,我从课程中下载了他的完整示例代码,并将他的记录器 class 库集成到我的项目中,看看它是否有效。

不幸的是,除了一个关键元素之外,一切似乎都有效。 在我项目的 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 课程是为其他试图这样做的人提供的,以拯救他们不得不像我一样经历同样的挣扎。

您可以尝试在自定义异常处理程序中间件中重置端点和路由值,如下所示。

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,
    };

//...

更多信息请查看github中的ExceptionHandlerMiddleware源码:

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

我实际上推荐了一种比我最初在 .NET Logging Done Right 课程中展示的更简单的方法(该课程大部分是围绕 .NET 框架构建的,并且在原始发布后添加了 ASP.NET 核心模块)。 进行 ASP.NET 核心日志记录的更好课程是 ASP.NET 核心中更新的有效日志记录。 但是,不要简单地将您送到另一门课程观看,请允许我回答您的问题。

我认为您应该使用UseExceptionHandler(string path)中间件。 您可以在错误代码(控制器或 razor 页面代码)中自由记录异常。 您可以在此代码仓库中具体看到这一点:

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

具体看BookClub.UI项目中的这些文件:

  • Startup.cs( Configure方法)
  • 页面/错误.cshtml
  • 页面/Error.cshtml.cs

这将使您的自定义代码保持在最低限度(总是一件好事)。

HTH

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM