解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题
我们基于 Razor Class Library 实现了自定义错误页面的公用类库(详见之前的随笔),但是在实际使用时发现如果在 middleware 中发生了异常,则不能显示自定义错误页面,而是返回默认的 500 空白页面。
public static IApplicationBuilder UseCustomErrorPages(this IApplicationBuilder app) {app.UseExceptionHandler("/errors/500");app.UseStatusCodePagesWithReExecute("/errors/{0}");return app; }
自定义错误页面使用的是上面的配置,当发生异常时,会走路由 /errors/500 到达对应的自定义错误页面的 mvc action 。 如果是 mvc 中产生异常,能正常到达;但是当 middleware 中产生异常时,在去往自定义错误页面的途中,又途径异常 middleware ,从而让自定义错误页面也产生了异常。这就是自定义错误页面不能显示的原因。
问题的原因想明白了,接下来通过集成测试重现这个问题。
public class ErrorPageTests : IClassFixture<WebApplicationFactory<Startup>> { [Fact]public async Task ErrorPageForMiddleWareException(){var client = _factory.WithWebHostBuilder(builder =>{builder.ConfigureServices(services => services.AddMvc());builder.Configure(app =>{app.UseCustomErrorPages();app.Use(next => context => throw new Exception("Failed in middleware"));app.UseMvcWithDefaultRoute(); });}).CreateClient();var response = await client.GetAsync("/");Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);var content = await response.Content.ReadAsStringAsync();Assert.Contains($"请求失败:500", content);} }
先写好测试的好处之一是在尝试解决方法时可以快速得到反馈,虽然写测试代码会花去更多时间,但仅这一点好处就得远大于失。
有了测试代码的保驾护航,这时就可以放心大胆的动手尝试解决问题了。
既然问题的根源是“在去往自定义错误页面的途中,又途径异常 middleware”,那我们只要抄近路绕过这些 middlewares ,直接奔向 asp.net core mvc 的 middleware ,问题不就解决了吗?
那怎么绕过去呢?不用 app.UseExceptionHandler ,自己写个 middleware ?先别做这个啥事,先搞清楚 app.UseExceptionHandler 究竟干了些啥?如果能通过 app.UseExceptionHandler 解决这个问题,岂不更好?
打开 app.UseExceptionHandler 所在的 github 仓库 Microsoft.AspNetCore.Diagnostics ,找到对应的中间件实现源码 ExceptionHandlerMiddleware ,下面的删减后的源码:
public class ExceptionHandlerMiddleware {//... public async Task Invoke(HttpContext context){try{await _next(context);}catch (Exception ex){//...PathString originalPath = context.Request.Path;if (_options.ExceptionHandlingPath.HasValue){context.Request.Path = _options.ExceptionHandlingPath;}try{//...await _options.ExceptionHandler(context); //... }//... }} }
原来在 ExceptionHandlerMiddleware 中只是将请求路径修改为 "/errors/500" 然后调用 ExceptionHandler ,但是我们在 app.UseExceptionHandler 只设置了请求路径,并没有设置 ExceptionHandler ,那就是默认 ExceptionHandler ,默认的 ExceptionHandler 是什么?
在 ExceptionHandlerMiddleware 的构造函数中找到了答案 —— 请求管线中的下一个中间件
if (_options.ExceptionHandler == null) {//..._options.ExceptionHandler = _next; }
只要将这里的 ExceptionHandler 修改为返回自定义错误页面的 handler ,问题就能解决。
ExceptionHandler 的类型是 RequestDelegate ,现在问题变成了如何在 RequestDelegate 中执行 mvc action 并返回响应内容?
在这个地方走了一些弯路,开始想通过 IActionResultExecutor 实现,但没成功。
后来想到最简单的方法就是利用已有的 mvc 中间件,基于 app.UseMvcWithDefaultRoute() 构建出 RequestDelegate 。基于这个思路,在 ExceptionHandlerExtensions 中以 Action<IApplicationBuilder> 为参数的扩展方法中学到一招:
var subAppBuilder = app.New(); configure(subAppBuilder); var exceptionHandlerPipeline = subAppBuilder.Build();return app.UseExceptionHandler(new ExceptionHandlerOptions {ExceptionHandler = exceptionHandlerPipeline });
原来可以如此简单地通过 IApplicationBuilder 构建出 RequestDelegate 。
通过学习的这一招完美地解决了问题!
public static IApplicationBuilder UseCustomErrorPages(this IApplicationBuilder app) {var options = new ExceptionHandlerOptions{ExceptionHandlingPath = "/errors/500",ExceptionHandler = app.New().UseMvcWithDefaultRoute().Build()};app.UseExceptionHandler(options);app.UseStatusCodePagesWithReExecute("/errors/{0}");return app; }
解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题相关推荐
- [转载]针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结
针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结 汪宇杰 2014-1-11 星期六 02:31 455 Reads 1 Comments 自定义错误页面和异常记录是个很古老的话题了, ...
- SpringBoot 错误页面使用、自定义错误页、自定义异常、自定义异常解析器
在SpringBoot使用错误页面非常的简单 一. 错误页面使用 二. 自定义错误页 三.自定义异常 四.自定义异常解析器 一. 错误页面使用 只需要在templates里创建一个error文件夹,然 ...
- asp.net core 自定义基于 HttpContext 的 Serilog Enricher
asp.net core 自定义基于 HttpContext 的 Serilog Enricher Intro 通过 HttpContext 我们可以拿到很多有用的信息,比如 Path/QuerySt ...
- asp.net core 自定义 Policy 替换 AllowAnonymous 的行为
asp.net core 自定义 Policy 替换 AllowAnonymous 的行为 Intro 最近对我们的服务进行了改造,原本内部服务在内部可以匿名调用,现在增加了限制,通过 identit ...
- nginx自定义错误页
文章目录 自定义错误页 1.为每种类型的错误设置单独的处理方式 2.利用在线资源进行处理错误 3.更改晌应状态码 4.设置错误页面案例 自定义错误页 在网站访问过程中,经常会遇见各种各样的错误,如找不 ...
- 升级到asp.net core 3.1遇到的json异常
升级到asp.net core 3.1遇到的json异常 参考文章: (1)升级到asp.net core 3.1遇到的json异常 (2)https://www.cnblogs.com/Wadere ...
- SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)
SpringBoot系列五:SpringBoot错误处理(数据验证.处理错误页.全局异常) 参考文章: (1)SpringBoot系列五:SpringBoot错误处理(数据验证.处理错误页.全局异常) ...
- ASP.NET Core WebAPI帮助页--Swagger简单使用1.0
1.什么是Swagger? Swagger是一个规范且完整的框架,提供描述.生产.消费和可视化RESTful API,它是为了解决Web API生成有用文档和帮助页的问题. 2.为啥选用swagger ...
- asp.net core自定义依赖注入容器,替换自带容器
依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...
最新文章
- 笔试分享 | 带你解读校招人工智能笔试题
- 论一名项目经理的能力素养
- FineUIMvc随笔(1)动态创建表格列
- linux下创建和删除软、硬链接
- HTTP协议(HyperText Transfer Protocol,超文本传输协议)
- django中的分页
- 计算机网络总结之计算机概述
- 脚本其实很简单-windows配置核查程序(1)
- 【转】矩阵的几何解释
- ubuntu每日构建版
- 前端学习(2559):双向数据和单向数据不冲突
- 16进制数组转字符串
- win7需要计算机管理员权限,Win7系统提示“需要管理员权限”如何解决?
- 关于MyEclips新导入项目报错问题,解决方法!(基础)
- matlab条形图颜色矩阵,matlab中的条形图开关颜色
- WinCE6.0+ S3C6410 IIC驱动源码学习
- 柱状图之最大矩形面积
- MAC 下开发 不区分大小写问题及解决
- 【解决方案】SkeyeVSS石油油田钻井无线智能视频监控系统解决方案
- 如何利用PS动作一秒将字体生成逼真刺绣效果
热门文章
- python与php8-php8的扩展arginfo生成工具及工具初体验
- python里面的之前打过的记忆信息-python中的if __name__ == 'main'
- python3.6.5安装教程-Ubuntu16.04安装python3.6.5步骤详解
- python快速编程入门黑马-新手如何快速入门Python编程?/开发python入门教程
- python中文叫什么意思-python中文叫什么
- 解决错误:No module named ‘Cryptodome‘ 和错误rosbag.bag.ROSBagException: unsupported compression type: lz4
- 蓝桥哈夫曼树C语言,实验四 哈夫曼树及哈夫曼编码
- 使用Callable来获取数组的最大值
- ClassNotFoundException和 NoClassDefFoundError区别验证
- 谨慎跟随初始目的不被关联问题带偏