c# - 如何让用 ASP.Net Core 2.0 编写的自定义异常处理程序在 ASP.Net Core 3.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 课程是为其他试图这样做的人提供的,以挽救他们不得不经历与我一样的挣扎。
解决方案
您可以尝试在自定义异常处理程序中间件中重置端点和路由值,如下所示。
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 中的源代码:
推荐阅读
- css - File Watcher 生成 .css 文件但不刷新浏览器也不应用 CSS 代码
- caching - 对于大量数据,缓存是否值得?
- python - 表达式中 a[:] 和 a 的区别
- c# - 如何获取源文件的路径?
- solr - Sitecore 7.2 - Solr 4 facet 搜索建议 - 搜索词中没有连字符的结果
- python-3.x - 自动发送电子邮件
- javascript - 如何通过 javascript / jquery 从服务器获取电子邮件
- vue.js - Vuetify 指令不遵循我的断点
- algorithm - 在画布上展开对象以最小化重叠
- jquery - jQuery不可关闭模式不尊重选项