Error Handling in ASP.NET Core
.NET-Core Series
- Server in ASP.NET-Core
- DI in ASP.NET-Core
- Routing in ASP.NET-Core
- Error Handling in ASP.NET-Core
- WebSocket in ASP.NET-Core(一)
- WebSocket in ASP.NET-Core(二)
- To be Continue...
Error Handling in ASP.NET Core
前言
在程序中,经常需要处理比如 404
,500
,502
等错误,如果直接返回错误的调用堆栈的具体信息,显然大部分的用户看到是一脸懵逼的,你应该需要给用户返回那些看得懂的界面。比如,“当前页面不存在了” 等等,本篇文章主要来讲讲 .NET-Core
中异常处理,以及如何自定义异常显示界面?,还有 如何定义自己的异常处理中间件?。
.NET-Core 中的异常处理
让我们从下面这段代码讲起,写过.Net-Core
的应该不陌生,在 Startup
的 Configure
中定义异常处理的中间件。
if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}else{
app.UseExceptionHandler("/error");
}
上面两种情况分别是一个是使用自带的异常处理,另外一个是将错误异常的处理,进行自己处理。两种情况如下所示:
我在HomeController
中定义了一个Test Action
如下所示(仅仅为了演示,并无实际意义)
//Controller
public string Test(int id){
if(id == 1){
return new System.NullReferenceException("It's not equals to 1, robert!");
}
return "Bingo,Robert!";
}
//Routing
routes.MapRoute(
name: "Error",
template: "error/",
defaults: new { controller = "Home", action = "error" }
);
使用 localhost:{port}/home/test/2
的结果像下面这样
对我localhost:{port}/home/test/1
这样呢,在不同环境下是不一样的,具体如下所示:
- UseDeveloperException
- UseExceptionHandler
这些呢,就是比较平常的 .NET-Core
的处理方式。但是看不见StatusCode
,发现没有,除了自定义的时候,默认时是不提供Status Code
的。这时候,就可以用到这个
UseStatusCodePages()
想要看源码的在这 StatusCodePagesExtension Source Code。
效果怎么样的呢?如下所示:
这是默认的处理方式,看了源码我们知道,UseStatusCodePages 有4个重载。还可以自己定义,是不是感觉比前面的高级点,下面是自定义:具体就不演示了。
app.UseStatusCodePages(async context =>{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync($"What's the statusCode you got is {context.HttpContext.Response.StatusCode}");
});
app.UseStatusCodePages("text/plain","What's the statusCode you got is {0}");
截止到上面为止,基本的异常处理其实已经介绍的差不多了。但是,总感觉那么普遍呢,好像还不够特殊,并且还满足不了我们的需求,我们想要自定义错误的处理方式。比如我们想要遇到 404 时就显示 404 界面。
定义异常处理中间件
其实上面的自定义自己的异常处理时,其实已经可以做到我们需要的情况了。我们在Error Action
中对 HttpContext.Response.StatusCode
进行判断,根据不同的StatusCode
return 不同的View
就可以了。但是为什么我们还需要定义特定处理的中间件,主要目的是为了其他项目服务的,如果你只有一个项目,一个站点,其实并没什么必要。但是如果有很多子站点时,还是需要考虑的一下的。
模仿了一下 UseStatusCodePagesWithReExecute
这个,写了一个
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Builder;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
namespace MiddlewareDemo.CustomMiddleware
{
/// <summary>
/// Adds a StatusCodePages middleware to the pipeline. Specifies that the response body should be generated by
/// re-executing the request pipeline using an alternate path. This path may contain a '{0}' placeholder of the status code.
/// </summary>
/// <param name="app"></param>
/// <param name="pathFormat"></param> //因为直接 处理404 所以就不给参数啦。
/// <param name="queryFormat"></param>
/// <returns></returns>
public static class ErrorHandlerMiddlewareExtension
{
public static IApplicationBuilder UseErrorHandler(
this IApplicationBuilder app,
string pathFormat = "/error",
string queryFormat = null)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseStatusCodePages(async context =>
{
if (context.HttpContext.Response.StatusCode == StatusCodes.Status404NotFound)
{
var newPath = new PathString(
string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
var formatedQueryString = queryFormat == null ? null :
string.Format(CultureInfo.InvariantCulture, queryFormat, context.HttpContext.Response.StatusCode);
var newQueryString = queryFormat == null ? QueryString.Empty : new QueryString(formatedQueryString);
var originalPath = context.HttpContext.Request.Path;
var originalQueryString = context.HttpContext.Request.QueryString;
// Store the original paths so the app can check it.
context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
{
OriginalPathBase = context.HttpContext.Request.PathBase.Value,
OriginalPath = originalPath.Value,
OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
});
context.HttpContext.Request.Path = newPath;
context.HttpContext.Request.QueryString = newQueryString;
try
{
await context.Next(context.HttpContext);
}
finally
{
context.HttpContext.Request.QueryString = originalQueryString;
context.HttpContext.Request.Path = originalPath;
context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(null);
}
}
});
}
}
}
这样就会只处理404啦。
如下所示 :
最后分享一个 Re-execute vs Redirect 的一位大神的分析
其实在 StatusCodePagesExtensions
中还有两个方法,这两个方法也会比较实用,主要是用来当遇到异常,给你跳转到其他界面的。
//使用的话就像下面这样就可以啦
app.UseStatusCodePagesWithReExecute("/error","?StatusCode={0}");
app.UseStatusCodePagesWithRedirects("/error");
//具体可以用哪些参数呢,可以去看源码,这里就不多介绍了。
这两个的虽然都可以得到我们想要的结果,但是过程差的有点多。先盗一下大神的两张图:
第一张是 Redirect
的 :
下面一张是 ReExecute` 的
区别呢,我用Chrome Developer Console
来给你们展示一下,你们就明白啦。
这个是 redirect
的 ,很神奇吧,它返回的是 200 ok
. 由于是 redirect
所以 地址 redirect 到了 localhost:52298/error
。看Network
可知,进行了两次请求,第一次,http://localhost:52298/home/testpage
时 返回302 Found
. 我们知道这个是 404 的状态码,被 middleware “抓到”后,于是,我们再次发起请求, http://localhost:52298/error
这个请求当然返回的状态码是 200 啦。所以我们在下图的结果中可以看见。200 OK。
302 : The 302 (Found) status code is used where the redirection is temporary or generally subject to change, such that the client shouldn't store and reuse the redirect URL in the future
下面的是 ReExecute
的
结语
如有陈述的不正确处,请多多评论指正。
文章推荐及参考链接
Error Handling in ASP.NET Core的更多相关文章
- Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)
目前,在Web API中没有简单的方法来记录或处理全局异常(webapi1中).一些未处理的异常可以通过exception filters进行处理,但是有许多情况exception filters无法 ...
- Global exception handling in asp.net core webapi
在.NET Core中MVC和WebAPI已经组合在一起,都继承了Controller,但是在处理错误时,就很不一样,MVC返回错误页面给浏览器,WebAPI返回Json或XML,而不是HTML.Us ...
- DI in ASP.NET Core
.NET-Core Series Server in ASP.NET-Core DI in ASP.NET-Core Routing in ASP.NET-Core Error Handling in ...
- Routing in ASP.NET Core
.NET-Core Series Server in ASP.NET-Core DI in ASP.NET-Core Routing in ASP.NET-Core Error Handling in ...
- WebSocket In ASP.NET Core(一)
.NET-Core Series Server in ASP.NET-Core DI in ASP.NET-Core Routing in ASP.NET-Core Error Handling in ...
- WebSocket In ASP.NET Core(二)
WebSocket In ASP.NET Core(二) Server in ASP.NET-Core DI in ASP.NET-Core Routing in ASP.NET-Core Error ...
- ASP.NET Core错误处理中间件[1]: 呈现错误信息
NuGet包"Microsoft.AspNetCore.Diagnostics"中提供了几个与异常处理相关的中间件.当ASP.NET Core应用在处理请求过程中出现错误时,我们可 ...
- 在ASP.NET Core使用Middleware模拟Custom Error Page功能
一.使用场景 在传统的ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAtt ...
- ASP.Net Core 运行错误 Http Error 502.5 解决办法
Http Error 502.5 - Process Failure 如果你看到上面这张图片了的话,说明你在本地运行的时候报错了. 尤其好多都是我的群友,说下情况. 这个一般是本地的.NET Core ...
随机推荐
- echarts 支持svg格式
今天研究了下echarts的svg格式.发现用ai生成svg格式的图片,echarts上面显示不了. 经过了多次的百度和谷歌终于找到了用Method Draw画出来的svg格式,echarts就能加载 ...
- vue+mockjs 模拟数据,实现前后端分离开发
在项目中尝试了mockjs,mock数据,实现前后端分离开发. 关于mockjs,官网描述的是 1.前后端分离 2.不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据. 3.数据类型丰 ...
- 让这三个月来的更猛烈些吧,前端react同构项目
昨天一篇文章讲述了我在这三个月中由.net到java的过程,其中踩坑填坑的细节真不是三言两语可以道尽,而完成时的喜悦也远非寻常可比(仅次于涨工资).然而到这并不算完结,作为前后端分离的忠实粉丝,我认为 ...
- Python使用PDFMiner解析PDF
近期在做爬虫时有时会遇到网站只提供pdf的情况,这样就不能使用scrapy直接抓取页面内容了,只能通过解析PDF的方式处理,目前的解决方案大致只有pyPDF和PDFMiner.因为据说PDFMiner ...
- 关于java中用itext导出word的一点想法
这几天在项目组只做了很少的事情,主要还是自己不认真地说.我的部分是要负责用itext导出word文档这一块,之前看到大佬们做出了EXCEL部分觉得很是惊奇,就像刚刚接触HTML一样的感觉.但是毕竟自己 ...
- leetcode range sum query
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...
- 解析SS、SP、BP寄存器
SS, SP, BP 三个寄存器 SS:存放栈的段地址: SP:堆栈寄存器SP(stack pointer)存放栈的偏移地址; BP: 基数指针寄存器BP(base pointer)是一个寄存器,它的 ...
- Redis和消息队列使用实战
消息队列是在乐视这边非常普遍使用的技术.在我们部门内部,不同的项目使用的消息队列实现也不一样.下面是支付系统的流转图(部门兄弟画的,借用一下): 从图中可以看到,里面用到了kafka消息队列.作用是做 ...
- 第7天:input和label标签
今天学的不多,就只学了表单元素中的input和label标签.搬了房子,收拾了一下东西,太累了,所以没有学很多.明天还上班,今天就先到这. 一.input input标签type属性有以下几个:tex ...
- C#使用Xamarin开发可移植移动应用进阶篇(6.使用渲染器针对单个平台自定义控件..很很很很重要..),附源码
前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. 本篇..基 ...