Error Handling in ASP.NET Core

前言

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

.NET-Core 中的异常处理

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

if (env.IsDevelopment()){app.UseDeveloperExceptionPage();
}else{app.UseExceptionHandler("/error");
}

  上面两种情况分别是一个是使用自带的异常处理,另外一个是将错误异常的处理,进行自己处理。两种情况如下所示:

我在HomeController 中定义了一个Test Action如下所示(仅仅为了演示,并无实际意义)

//Controllerpublic string Test(int id){    if(id == 1){        return new System.NullReferenceException("It's not equals to 1, robert!");}  return "Bingo,Robert!";
}//Routingroutes.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 的

结语

  如有陈述的不正确处,请多多评论指正。

文章推荐及参考链接

  • Use statusCodeWithReExecute and pic reference

  • StatusCodePagesExtensions Source Code

相关文章: 

  • .NET Core 2.0 正式发布信息汇总

  • .NET Standard 2.0 特性介绍和使用指南

  • .NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决

  • .NET Core 2.0 特性介绍和使用指南

  • Entity Framework Core 2.0 新特性

  • 体验 PHP under .NET Core

  • .NET Core 2.0使用NLog

  • 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

  • 解决Visual Studio For Mac Restore失败的问题

  • ASP.NET Core 2.0 特性介绍和使用指南

  • .Net Core下通过Proxy 模式 使用 WCF

  • .NET Core 2.0 开源Office组件 NPOI

  • ASP.NET Core - Razor页面之Handlers处理方法

  • ASP.NET Core Razor页面 vs MVC

  • Razor Page–Asp.Net Core 2.0新功能  Razor Page介绍

  • ASP.Net Core 2.0中的Razor Page不是WebForm

原文地址:http://www.cnblogs.com/xiyin/p/7507405.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于python的selenium

一.安装 安装WebDriver 查看chrome版本号&#xff0c;设置-帮助-关于Google chrome&#xff0c;找到版本号。 可以到这个网站进行下载对应版本的chromedriver,如果chrome浏览器版本过高,可以下载最新版的chromedriver进行使用 Chrome for Testing availability 下载下来之后…

多信息登录、检测用户信息是否完善且引导补全

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注&#xff1a;穆雄雄的博客 前言 现在是2022年4月28日13:41:29&#xff01; 今天分享两块内容。 1.需求&#xff1a;用户可以通过手机号、邮箱来注册我们的系统&#xff0c;用户完成之后&#xff0c;可以去完善自己的个人信息…

PNG 图片压缩原理解析

转载自 PNG 图片压缩原理解析 什么是PNG PNG的全称叫便携式网络图型&#xff08;Portable Network Graphics&#xff09;是目前最流行的网络传输和展示的图片格式&#xff0c;原因有如下几点&#xff1a; 无损压缩&#xff1a;PNG图片采取了基于LZ77派生算法对文件进行压缩&…

element ui实现多层级复杂表单的操作(添加与回显)之表单操作交互操作

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月3日11:47:15&#xff01;劳动节假期已经过去了三天了&#xff0c;今天是被封家里的第7天&#xff0c;也是解封的第一天。 说实话&#xff0c;在家里的工作效率一点都…

TypeScript 2.5 发布,增加语言级重构

在 TypeScript 2.5 版本中&#xff0c;Microsoft 专注于提高开发人员的生产力&#xff0c;其范围已经超出了代码编辑器所提供的常见功能。 习惯于类型语言&#xff08;如 C&#xff03;&#xff09;的开发人员喜欢使用那些可以轻松执行常见重构的工具。现在 TypeScript 可以利…

element ui实现多层级复杂表单的操作(添加与回显)之添加功能实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月3日13:35:15&#xff01;文接上篇。[element ui实现多层级复杂表单的操作&#xff08;添加与回显&#xff09;之表单操作交互操作](element ui实现多层级复杂表单的操…

Entity Framework Core Like 查询揭秘

在Entity Framework Core 2.0中增加一个很酷的功能&#xff1a;EF.Functions.Like()&#xff0c;最终解析为SQL中的Like语句&#xff0c;以便于在 LINQ 查询中直接调用。 不过Entity Framework 中默认提供了StartsWith、Contains和EndsWith方法用于解决模糊查询&#xff0c;那…

element ui实现多层级复杂表单的操作(添加与回显)之回显功能实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月3日17:02:30&#xff01;文接上两篇。 [element ui实现多层级复杂表单的操作&#xff08;添加与回显&#xff09;之表单操作交互操作](element ui实现多层级复杂表单…

在Mac的Docker中运行DotNetCore2.0

最近学习Angular4&#xff0c;服务端准备使用DotNetCore API来实现&#xff0c;本文简单介绍下在Mac中怎样将DotNetCore程序部署在Docker中&#xff0c;并使用Nginx做反向代理让程序可以跑起来。 具体步骤如下 安装Docker拉取DotNetCore镜像使用VS For Mac创建DotNetCore应用…

springboot实现复杂业务下的更新操作

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月4日19:25:55&#xff01;今天写了个这样的功能&#xff1a; 某用户在一天内有多个训练项目&#xff0c;比如&#xff1a;晨跑&#xff0c;有氧训练&#xff0c;跳绳这…

elementui解决el-dialog不清空内容的问题,el-dialog关闭时销毁子组件

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月5日22:48:21&#xff01; 今天在使用element-ui中的el-dialog的时候遇到了个这样的问题&#xff1a;页面上点击添加的按钮&#xff0c;弹出el-dialog对话框&#xff…

MySQL 中的重做日志,回滚日志以及二进制日志的简单总结

转载自 MySQL 中的重做日志&#xff0c;回滚日志以及二进制日志的简单总结 MySQL中有六种日志文件&#xff0c;分别是&#xff1a;重做日志&#xff08;redo log&#xff09;、回滚日志&#xff08;undo log&#xff09;、二进制日志&#xff08;binlog&#xff09;、错误日志…

c语言分离三位数

#include<stdio.h> main(){ int k,l,m,n;printf("请输入一个三位数"); scanf("%d",&k);lk/100;mk/10%10;nk%10;printf("这个三位数的百位是:%d\n",l);printf("这个三位数的十位是:%d\n",m);printf("这个三位数的个位是…

分布式ID自增算法 Snowflake

近在尝试EF的多数据库移植&#xff0c;但是原始项目中主键用的Sqlserver的GUID。MySQL没法移植了。 其实发现GUID也没法保证数据的递增性&#xff0c;又不太想使用int递增主键&#xff0c;就开始探索别的ID形式。 后来发现twitter的Snowflake算法。 一开始我尝试过直接引用N…

java中,根据指定日期显示出前n天的日期

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 今天分享的是&#xff1a;在java中&#xff0c;根据指定日期显示出前n天的日期 效果如下&#xff1a; 大家注意观察上面的时间&#xff0c;我传入的时间是&#xff1a;2022年5月9日21:28:…

jdbc实现批量给多个表中更新数据(解析Excel表数据插入到数据库中)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月19日08:01:51 今天遇到了个这样的需求&#xff0c;解析excel表中的数据&#xff0c;以JDBC的方式&#xff0c;将数据批量更新至不同的数据表中。注意&am…

.Net Core 全局配置读取管理方法 ConfigurationManager

最近在学习.Net Core的过程中&#xff0c;发现.Net Framework中常用的ConfigurationManager在Core中竟然被干掉了。 也能理解。Core中使用的配置文件全是Json&#xff0c;不像Framework使用的XML&#xff0c;暂时不支持也是能理解的&#xff0c;但是毕竟全局配置文件这种东西还…

Http 持久连接与 HttpClient 连接池

转载自 Http 持久连接与 HttpClient 连接池 一、背景 HTTP协议是无状态的协议&#xff0c;即每一次请求都是互相独立的。因此它的最初实现是&#xff0c;每一个http请求都会打开一个tcp socket连接&#xff0c;当交互完毕后会关闭这个连接。 HTTP协议是全双工的协议&#x…

jdbc解析excel文件,批量插入数据至库中

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年5月20日09:32:38今天遇到了个这样的需求&#xff0c;解析excel表中的数据&#xff0c;以JDBC的方式&#xff0c;将数据批量更新至不同的数据表中。注意&…

线程2

public class test{/*** 测试延迟继承* param args*/public static void main(String[] args) {Cat catnew Cat();cat.start();//启动线程&#xff0c;会导致run函数的运行Dog dognew Dog();//创建一个线程对象Thread tnew Thread(dog);t.start();}} //继承Thread创建线程 clas…