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 -*- ''''' python中的输出为print ...
- Linux基本命令整理_sheng
Linux版本 Linux系统是一个多用户.多任务的分时操作系统. Linux版本分为内核版本和发行版本. 常见的Linux发行版有: RedHat(分为用于企业的Red Hat Enterprise ...
- EF 中 Code First 的数据迁移以及创建视图
写在前面: EF 中 Code First 的数据迁移网上有很多资料,我这份并没什么特别.Code First 创建视图网上也有很多资料,但好像很麻烦,而且亲测好像是无效的方法(可能是我太笨,没搞成功 ...
- Linux服务器中安装Oracle
笔者手动安装成功 一,oracle安装前的准备与配置 1,修改stsctl.conf文件 Linux是为小文件设计的,Oracle数据库安装需要占用较多资源,要把各项参数调大. 使用vi编辑/etc/ ...
- little bird
LITTLE BIRD Bzoj 3831 相对而言是一道比较简单的DP,不过它需要用单调队列优化.首先是朴素O(n2), if(d[j]>f[i]) f[i]=min(f[i],f[j]); ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第三节--abp分层体系及实体相关
说了这么久,还没有详细说到abp框架,abp其实基于DDD(领域驱动设计)原则的细看分层如下: 再看我们项目解决方案如下: JCmsErp.Application,应用层:进行展现层与领域层之间的协调 ...
- python--DenyHttp项目(1)--GUI:tkinter☞ module 'tkinter' has no attribute 'messagebox'
AttributeError: module 'tkinter' has no attribute 'messagebox' improt tkinter from tkinter import * ...
- Mysql MHA(GTID)配置(实操)
实现环境 centos6.7 MYSQL5.6.36 主:192.168.1.191 从1:192.168.1.145 从2:192.168.1.146 监测:放在从2上 192.168.1.146 ...
- 一些常用的集合工具的代码块(缓慢更新XD)
鱼的记忆 我发现在项目中常常要用到一些集合的处理,不同的项目我经常会编写自己的集合工具代码块,后来我发现我总是在写一样的代码块(可能是我记性不好吧:),毕竟鱼的记忆只有7秒),所以我意识到了是时候 ...
- iOS 10 UserNotification框架解析 – 本地通知
iOS 10以前的通知比较杂乱,把本地通知和远程通知分开了,诞生了许多功能类似的API,很容易让初学者犯迷糊.而iOS 10的通知把API做了统一,利用独立的UserNotifications.fra ...