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 ...
随机推荐
- ES6数字扩展
前面的话 本文将详细介绍ES6数字扩展 指数运算符 ES2016引入的唯一一个JS语法变化是求幂运算符,它是一种将指数应用于基数的数学运算.JS已有的Math.pow()方法可以执行求幂运算,但它也是 ...
- FaceRank-人脸打分基于 TensorFlow 的 CNN 模型
FaceRank-人脸打分基于 TensorFlow 的 CNN 模型 隐私 因为隐私问题,训练图片集并不提供,稍微可能会放一些卡通图片. 数据集 130张 128*128 张网络图片,图片名: 1- ...
- 2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼
2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼 转眼又已过去了一年,在这一年里,Firefox 和 Chrome 在拼升级,版本号不断飙升:IE10 随着 Windows 8 在 ...
- 框架 之 -------Spring
目录一.Spring工作原理 二.为什么要用Spring三.请你谈谈SSH整合四.介绍一下Spring的事务管理五.什么是依赖注入,依赖注入的作用是什么? 六.什么是AOP,AOP的作用是什么? 七. ...
- 14. leetcode 383. Ransom Note
Given an arbitrary ransom note string and another string containing letters from all the magazines, ...
- 使用Node.js调用阿里云短信的发送以及接收
为了使用Node.js调用阿里云短信服务,我自己写了个npm包, 目前实现了: 使用Node.js调用阿里云短信服务,发送短信: 使用Node.js调用阿里云短信服务以及MNS服务,接收用户上行短信 ...
- Go的类型断言解析
经常地我们对一个接口值的动态类型是不确定的,如方法的形参为接口类型时,此时就需要检验它是否符合我们需要的类型.类型断言是一个使用在接口值上的操作.断言类型的语法:x.(T),这里x表示一个接口的类型, ...
- [NOIP2009] 靶形数独 骚气的大爆搜
这两天OD留的题是搜索,这个东西,就是历年的NOIP压轴题嘛.做了几道什么斗地主啊啥的,感觉还是这题我还懂点. 这道题的搜(xia)索(da)思路是这样的:预处理出一切能处理的东西. 数独大家都了解吧 ...
- 开心的金明 NOIP 2006 普及组
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就 ...
- shell运算符之 关系运算符,算数运算符,布尔运算符,字符串运算符和文件测试运算符
shell运算符有很多,关系运算符,算数运算符,布尔运算符,字符串运算符和文件测试运算符 1,算术运算符 原声bash 不支持简单的算术运算,可以使用expr 工具 两点注意: 表达式和运算符之间要有 ...










