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

一、使用场景

  在传统的ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAttribute特性,那么默认的,当这个Action抛出了异常时MVC将会显示Error视图,该视图位于~/Views/Shared目录下。

  自定义错误页面的目的,就是为了能让程序在出现错误/异常的时候,能够有较好的显示体验。有时候在Error视图中也会发生错误,这时ASP.NET/MVC将会显示其默认的错误页面(黄底红字),为了避免这种情况的出现,我们都是在Web.config文件的customErrors节中来自定义错误页面,来启用自定义错误处理:

<configuration>
  <system.web>
    <compilation debug="true" />
    <customErrors mode="On" defaultRedirect="DefaultError">
      <error statusCode="401" redirect="Http401Error"/>
      <error statusCode="403" redirect="Http403Error"/>
      <error statusCode="404" redirect="Http404Error"/>
      <error statusCode="500" redirect="Http500Error"/>
    </customErrors>
  </system.web>
</configuration>

二、.NET Core实现

  既然想用ASP.NET Core中的中间件模拟Custom Error Page功能,那首先我从配置下手。大家都知道.NET Core中配置文件系统发生了很大的变化,默认都是采用Json格式的文件进行存储的,当然配置文件也可以是其它类型的,这里我们就不深入探讨了,我们就围绕Json配置文件实现好了:

"ErrorPages": {
  "401": "/Error/Http401Page",
  "403": "/Error/Http403Page",
  "404": "/Error/Http404Page",
  "500": "/Error/Http500Page"
}

  我们在Startup类中定义两个变量,用来存储配置文件读取出来的信息如下:

public IConfigurationRoot Configuration { get; }

internal static IDictionary<int, string> ErrorPages { get; } = new Dictionary<int, string>();

  配置文件中定义的ErrorPages节点,用于存储我们需要的Http状态编码并包含使用到的错误页面地址, 将他们用Startup类中的ErrorPages变量使用Key/Value的形式,读取出来。

  接下来我们要从JSON配置文件中读取信息填充到ErrorPages:

var builder = new ConfigurationBuilder()
    .SetBasePath(env.ContentRootPath)
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
    .AddEnvironmentVariables();

Configuration = builder.Build();

foreach (var c in Configuration.GetSection("ErrorPages").GetChildren())
{
    var key = Convert.ToInt32(c.Key);
    if (!ErrorPages.Keys.Contains(key))
    {
        ErrorPages.Add(key, c.Value);
    }
}

  现在我们使用今天的主角,创建一个ASP.NET Core的Middleware,用于实现Custom Error Page功能:

public class CustomErrorPagesMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public CustomErrorPagesMiddleware(ILoggerFactory loggerFactory, RequestDelegate next)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<CustomErrorPagesMiddleware>();
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(0, ex, "An unhandled exception has occurred while executing the request");

            if (context.Response.HasStarted)
            {
                _logger.LogWarning("The response has already started, the error page middleware will not be executed.");
                throw;
            }
            try
            {
                context.Response.Clear();
                context.Response.StatusCode = 500;
                return;
            }
            catch (Exception ex2)
            {
                _logger.LogError(0, ex2, "An exception was thrown attempting to display the error page.");
            }
            throw;
        }
        finally
        {
            var statusCode = context.Response.StatusCode;

            if (Startup.ErrorPages.Keys.Contains(statusCode))
            {
                context.Request.Path = Startup.ErrorPages[statusCode];
                await _next(context);
            }
        }
    }

  这样就完成了,从响应Response的StatusCode到配置的具体页面的跳转。

  当然我们最后,还要为这个中间件添加一个扩展方法,ASP.NET Core中为 IApplictionBuilder创建了好多的扩展方法,其实也好比它的名子一样,它就应该是一个建造者模式。

  扩展方法如下:

public static class BuilderExtensions
{
    public static IApplicationBuilder UseCustomErrorPages(this IApplicationBuilder app)
    {
        return app.UseMiddleware<CustomErrorPagesMiddleware>();
    }
}

  最后在Startup类中的Configure方法中加入自定义错误的扩展:

app.UseCustomErrorPages();

三、源代码

  如果你对文中的代码感兴趣,也可以到我的Github上去看下这个例子的源代码:https://github.com/maxzhang1985/CustomErrorPages

------------------分割线--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  开源推广:  

  YOYOFx,一个轻量级用于构建基于 HTTP 的 Web 服务,支持.NET Framework 、.NET  CORE、 Mono 平台。

  本着学习的态度,造了这个轮子,也是为了更好的了解各个框架的原理和有点,还希望可以和大家多交流 。

  GitHub:https://github.com/maxzhang1985/YOYOFx  Star下, 欢迎一起交流。 .NET Core 和 YOYOFx 的交流群: 214741894

  如果你觉得本文对你有帮助,请点击“推荐”,谢谢。

时间: 2024-10-05 23:09:12

在ASP.NET Core使用Middleware模拟Custom Error Page功能的相关文章

ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因为WCF中不仅仅只是有SOAP, 它还包含很多如消息安全性,生成WSDL,双工信道,非HTTP传输等. ASP.NET Core 官方推荐大家使用RESTful Web API的解决方案提供网络服务. SOAP 即 Simple Object AccessProtocol 也就是简单对象访问协议.

ASP.NET Core中Middleware的使用

ASP.NET 5中Middleware的基本用法 在ASP.NET 5里面引入了OWIN的概念,大致意思是将网站部署.服务器.中间组件以及应用分离开,这里提到的Middleware就是中间组件. 这里引用asp.net网站的介绍图 Middleware的作用有点类似于httpmodule,服务器接收到的请求都会传递到各个Middleware,多个Middleware形成一个处理管道. 由于不针对于特定的请求,所以Middleware的执行范围是在Application之外,这种模式很适合处理日

说说ASP.Net Core 2.0中的Razor Page

随着.net core2.0的发布,我们可以创建2.0的web应用了.2.0中新东西的出现,会让我们忘记老的东西,他就是Razor Page.下面的这篇博客将会介绍ASP.Net Core 2.0中的Razor Page. 在ASP.Net Core 2.0新特点之一就是支持Razor Page.今天的Razor Page是ASP.Net Core MVC中的一个子集.ASP.Net Core MVC 支持Razor Page意味着Razor Page应用从技术上来说就是MVC应用,同时Razo

用ASP.NET Core 1.0中实现邮件发送功能-阿里云邮件推送篇

在上篇中用MailKit实现了Asp.net core 邮件发送功能,但一直未解决阿里云邮件推送问题,提交工单一开始的回复不尽如人意,比如您的网络问题,您的用户名密码不正确等,但继续沟通下阿里云客户还是很耐心的. 最终结论,是由于MailKit发送了两次EHLO命令,查看了MailKit源码后竟然发现,里面写了硬编码: if (host != "smtp.strato.de" && host != "smtp.sina.com") Ehlo (can

用ASP.NET Core 1.0中实现邮件发送功能

准备将一些项目迁移到 asp.net core 先从封装类库入手,在遇到邮件发送类时发现在 asp.net core 1.0中并示提供SMTP相关类库,于是网上一搜发现了MailKit 好东西一定要试一下,何况是开源,下面是代码可实现SMTP邮件发送: using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using System.Threading.Tasks; namespace ConsoleApp1 { public

学习ASP.NET Core Razor 编程系列九——增加查询功能

学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET Core Razor 编程系列三——创建数据表及创建项目基本页面 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面 学习ASP.NET Core Razor 编程系列五——Asp.Net Core Razor新建模板页面 学习ASP.NET C

Asp.Net管道模型和Asp.Net Core的Middleware模型的对比

原文地址:https://www.cnblogs.com/ghostdao/p/10843763.html

[转]Create Custom Exception Filter in ASP.NET Core

本文转自:http://www.binaryintellect.net/articles/5df6e275-1148-45a1-a8b3-0ba2c7c9cea1.aspx In my previous article I explained how errors in an ASP.NET Core web application can be dealt with  using middleware. I also mentioned that time that you can also

使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(四)-- Middleware

本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Middleware功能支持. 在演示Middleware功能之前,先要了解一下Asp.Net管道模型发生了什么样的变化. 第一部分:管道模型 1. Asp.Net管道 在之前的Asp.Net里,主要的管道模型流程如下图所示: 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象,封装此次请求有关的所有信息,然后进入HttpRuntime类进行进一步处理.H