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 ...
随机推荐
- 初学 Python(十一)——切片
初学 Python(十一)--切片 初学 Python,主要整理一些学习到的知识点,这次是切片. #-*- coding:utf-8 -*- ''''' 切片 ''' L = ['name','age ...
- 【原创】Easyui tree filter 过滤本地数据无效的原因
Easyui tree filter 过滤本地数据无效的解决方式 正确使用方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...
- [补档][HNOI 2008]GT考试
[HNOI 2008]GT考试 题目 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字. 他的不吉利数学A1A2... ...
- factorOne cannot be&nb…
factorOne cannot be resolved or is not a field 现象描述: Eclipse的使用时会在代码处出现警告factorOne cannot be resolve ...
- jQuery防京东浮动网站楼层导航代码
jQuery防京东浮动网站楼层导航代码 <!DOCTYPE html > <html xmlns="http://www.w3.org/1999/xhtml" ...
- Android Gesture 手势创建以及使用示例
在Android1.6的模拟器里面预装了一个叫Gestures Builder的程序,这个程序就是让你创建自己的手势的(Gestures Builder的源代码在sdk问samples里面有,有兴趣可 ...
- mysql 查询性能优化第一章 为什么查询速度会慢
一 为什么查询速度会慢 在尝试编写快速的查询之前,咱们需要清除一点,真正重要的是响应时间.如果把查询看成是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要有 优化查询,实际上要 ...
- MapReduce最大值
package com.bw.hadoop;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import ...
- 手脱UPX(堆栈平衡原理)
一开始看到pushad F8执行直到只有esp,eip,变化 在esp处follow in dump 下硬件访问断点 F9运行在硬件断点停下 到达一个长跳转(跳到OEP) 完成 ----------- ...
- C#使用Xamarin开发可移植移动应用(3.Xamarin.Views控件)附源码
前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. .NET ...










