.NET-Core Series

Error Handling in ASP.NET Core

前言

 在程序中,经常需要处理比如 404 500502等错误,如果直接返回错误的调用堆栈的具体信息,显然大部分的用户看到是一脸懵逼的,你应该需要给用户返回那些看得懂的界面。比如,“当前页面不存在了” 等等,本篇文章主要来讲讲 .NET-Core 中异常处理,以及如何自定义异常显示界面?,还有 如何定义自己的异常处理中间件?。

.NET-Core 中的异常处理

 让我们从下面这段代码讲起,写过.Net-Core 的应该不陌生,在 StartupConfigure 中定义异常处理的中间件。

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的更多相关文章

  1. Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)

    目前,在Web API中没有简单的方法来记录或处理全局异常(webapi1中).一些未处理的异常可以通过exception filters进行处理,但是有许多情况exception filters无法 ...

  2. Global exception handling in asp.net core webapi

    在.NET Core中MVC和WebAPI已经组合在一起,都继承了Controller,但是在处理错误时,就很不一样,MVC返回错误页面给浏览器,WebAPI返回Json或XML,而不是HTML.Us ...

  3. 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 ...

  4. 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 ...

  5. 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 ...

  6. 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 ...

  7. ASP.NET Core错误处理中间件[1]: 呈现错误信息

    NuGet包"Microsoft.AspNetCore.Diagnostics"中提供了几个与异常处理相关的中间件.当ASP.NET Core应用在处理请求过程中出现错误时,我们可 ...

  8. 在ASP.NET Core使用Middleware模拟Custom Error Page功能

    一.使用场景 在传统的ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAtt ...

  9. ASP.Net Core 运行错误 Http Error 502.5 解决办法

    Http Error 502.5 - Process Failure 如果你看到上面这张图片了的话,说明你在本地运行的时候报错了. 尤其好多都是我的群友,说下情况. 这个一般是本地的.NET Core ...

随机推荐

  1. 从equals和==的区别开始

    今天我要谈的,不是具体的一个小程序的设计,也不是什么高大上的遗传算法群体智能什么什么的理念.今天我想就非常简单的一个问题,深入地解释一些东西,把自己的一些看法传达给大家.我相信,认真看下去,大家会有所 ...

  2. MongoDB3.4安装配置以及与Robomongo1.1的连接——解决Authentication Failed导致的不能连接问题

    本文环境:win10(64)+MongoDB(3.4.5)+Robomongo(1.1) 目录: MongoDB的安装 MongoDB的配置 Robomongo的安装以及与MongoDB的连接 一些新 ...

  3. poj-2287---Tian Ji -- The Horse Racing

    #include<iostream> #include<algorithm> using namespace std; bool cmp(const int,const int ...

  4. 微信小程序(有始有终,全部代码)开发--- 新增模块: 图片选取以及拍照功能

    开篇语 前几天发了一篇: <简年15: 微信小程序(有始有终,全部代码)开发---跑步App+音乐播放器 > 后来又发了BUG修复的版本: 简年18: 微信小程序(有始有终,全部代码)开发 ...

  5. WebServices客户端代码生成

    方式一: 官网下载cxf运行包:http://cxf.apache.org/download.html axis2:http://axis.apache.org/axis2/java/core/dow ...

  6. 【HTTP权威指南】第三章-HTTP报文

    HTTP是因特网的信使,报文就是信使运送的包裹. 这一章包含: 报文如何流动 报文的三个组成部分(起始行,首部,实体的主体部分) 请求报文和响应报文的区别 请求报文支持的各种功能(方法) 响应报文返回 ...

  7. 【IP限制】验证是否限制了境外IP访问权限

    为啥要限制境外IP访问咱们的网站或者服务呢?怕泄漏了"机密"(好像都是我们在山寨别人,哪儿TM有机密,那叫"鸡贼") 好像国外的网站也没有限制咱大陆客去访问,反 ...

  8. 验证码的Java实现--jsp

    <%@ page language="java" pageEncoding="UTF-8" %> <%@ page contentType=& ...

  9. windows 注入 之 SetWindowHookEx

    前面的项目用到hook 还是在半年前,没想到最近有用到了,说实话,在项目组就提出,能用别的办法还是不要用这种,毕竟不太正道(感觉哈). 最近又牵扯到第三方对接的任务,没办法我又回到了HOOK上了.与窗 ...

  10. Python Class System

    1.序言 本文旨在说明:在Python里自定义class时,方法的第一个参数必须是该class的instance自身的引用(一般用self命名). 在其他语言里,定义方法的时候,第一个参数不必是类实例 ...