• 在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  

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

  • 相关阅读:
    Linux设置静态IP
    jenkins+findbugs
    CentOS 6.6 安装 Node.js
    未来物联网、人工智能无法迈过的技术是什么
    未来物联网、人工智能无法迈过的技术是什么
    spss-数据清洗-处理重复数据
    spss-数据清洗-处理重复数据
    大数据时代数据管理方式研究
    大数据时代数据管理方式研究
    Excel表格文本格式的数字和数字格式如何批量转换
  • 原文地址:https://www.cnblogs.com/maxzhang1985/p/5974429.html
Copyright © 2020-2023  润新知