首页 程序笔记 全局处理ASP.NET Core异常错误的几种方法

全局处理ASP.NET Core异常错误的几种方法

异常处理程序页

若要为生产环境配置自定义错误处理页,请调用 UseExceptionHandler。 此异常处理中间件:

捕获并记录未经处理的异常。 使用指示的路径在备用管道中重新执行请求。 如果响应已启动,则不会重新执行请求。 模板生成的代码使用 /Error 路径重新执行请求。

由于此中间件可以重新执行请求管道:

中间件需要处理具有相同请求的重新进入。 这通常意味着在调用 _next 后清理它们的状态,或在 HttpContext 上缓存它们的处理以避免重做。 在处理请求正文时,这意味着缓冲或缓存结果(如表单读取器)。 对于模板中使用的 UseExceptionHandler(IApplicationBuilder, String) 重载,只会修改请求路径,并清除路由数据。 请求数据(如标头、方法和项)均按原样重复使用。 限定范围内的服务保持不变。

在下面的示例中,UseExceptionHandler 在非开发环境中添加异常处理中间件:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Razor Pages 应用模板在 Pages 文件夹中提供了一个“错误”页面 (.cshtml) 和 PageModel 类 (ErrorModel)。 对于 MVC 应用,项目模板包括 Error 操作方法和 Home 控制器的错误视图。

MVC的话同理,可以创建一个Error页面处理和显示错误页面。

异常处理中间件使用原始 HTTP 方法重新执行请求。 如果错误处理程序终结点限制为一组特定的 HTTP 方法,那么只会对这些 HTTP 方法运行。 例如,使用 [HttpGet] 属性的 MVC 控制器操作仅对 GET 请求运行。 若要确保所有请求都到达自定义错误处理页,请不要将它们限制为一组特定的 HTTP 方法。

根据原始 HTTP 方法以不同方式处理异常:

对于 Razor Pages,创建多个处理程序方法。 例如,使用 OnGet 处理 GET 异常,使用 OnPost 处理 POST 异常。

对于 MVC,请将 HTTP 谓词属性应用于多个操作。 例如,使用 [HttpGet] 处理 GET 异常,使用 [HttpPost] 处理 POST 异常。

若要允许未经身份验证的用户查看自定义错误处理页,请确保它支持匿名访问。

使用 IExceptionHandlerPathFeature 访问错误处理程序中的异常和原始请求路径。 以下示例使用 IExceptionHandlerPathFeature 获取有关引发的异常详细信息:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
    public string? RequestId { get; set; }

    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

    public string? ExceptionMessage { get; set; }

    public void OnGet()
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;

        var exceptionHandlerPathFeature =
            HttpContext.Features.Get<IExceptionHandlerPathFeature>();

        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            ExceptionMessage = "The file was not found.";
        }

        if (exceptionHandlerPathFeature?.Path == "/")
        {
            ExceptionMessage ??= string.Empty;
            ExceptionMessage += " Page: Home.";
        }
    }
}

异常处理程序 lambda

自定义异常处理程序页的替代方法是向 UseExceptionHandler 提供 lambda。 使用 lambda,可以在返回响应前访问错误。

以下代码使用 lambda 处理异常:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(exceptionHandlerApp =>
    {
        exceptionHandlerApp.Run(async context =>
        {
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;

            // using static System.Net.Mime.MediaTypeNames;
            context.Response.ContentType = Text.Plain;

            await context.Response.WriteAsync("An exception was thrown.");

            var exceptionHandlerPathFeature =
                context.Features.Get<IExceptionHandlerPathFeature>();

            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
            {
                await context.Response.WriteAsync(" The file was not found.");
            }

            if (exceptionHandlerPathFeature?.Path == "/")
            {
                await context.Response.WriteAsync(" Page: Home.");
            }
        });
    });

    app.UseHsts();
}

实现IExceptionHandler接口

IExceptionHandler 是接口,可为开发人员提供用于在中心位置处理已知异常的回叫。

IExceptionHandler 实现是通过调用 IServiceCollection.AddExceptionHandler<T> 来注册的。 IExceptionHandler 实例的生存期是 singleton。 可以添加多个实现,并按注册顺序调用它们。

如果异常处理程序处理请求,它可以返回 true 来停止处理。 如果异常不是由任何异常处理程序处理,则控件将回退到中间件的默认行为和选项。 对于已处理和未经处理的异常,会发出不同的指标和日志。

以下示例说明了 IExceptionHandler 实现:

using Microsoft.AspNetCore.Diagnostics;

namespace ErrorHandlingSample
{
    public class CustomExceptionHandler : IExceptionHandler
    {
        private readonly ILogger<CustomExceptionHandler> logger;
        public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
        {
            this.logger = logger;
        }
        public ValueTask<bool> TryHandleAsync(
            HttpContext httpContext,
            Exception exception,
            CancellationToken cancellationToken)
        {
            var exceptionMessage = exception.Message;
            logger.LogError(
                "Error Message: {exceptionMessage}, Time of occurrence {time}",
                exceptionMessage, DateTime.UtcNow);
            // Return false to continue with the default behavior
            // - or - return true to signal that this exception is handled
            return ValueTask.FromResult(false);
        }
    }
}

以下示例显示了在program.cs文件里为依赖项注入注册 IExceptionHandler 实现:

using ErrorHandlingSample;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
builder.Services.AddExceptionHandler<CustomExceptionHandler>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

// Remaining Program.cs code omitted for brevity

UseStatusCodePages

默认情况下,ASP.NET Core 应用不会为 HTTP 错误状态代码(如“404 - 未找到”)提供状态代码页。 当应用设置没有正文的 HTTP 400-599 错误状态代码时,它将返回状态代码和空响应正文。 若要启用常见错误状态代码的默认纯文本处理程序,请在 Program.cs 中调用 UseStatusCodePages:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages();

在请求处理中间件之前调用 UseStatusCodePages。 例如,在静态文件中间件和端点中间件之前调用 UseStatusCodePages。

未使用 UseStatusCodePages 时,导航到没有终结点的 URL 会返回一条与浏览器相关的错误消息,指示找不到终结点。 调用 UseStatusCodePages 时,浏览器将返回以下响应:

Status Code: 404; Not Found

UseStatusCodePages 通常不在生产中使用,因为它返回对用户没有用的消息。状态代码页中间件不捕获异常。 若要提供自定义错误处理页,请使用异常处理程序页。

UseStatusCodePagesWithRedirects

UseStatusCodePagesWithRedirects 扩展方法:

向客户端发送“302 - 已找到”状态代码。

将客户端重定向到 URL 模板中提供的错误处理终结点。 错误处理终结点通常会显示错误信息并返回 HTTP 200。

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

URL 模板可能会包括状态代码的 {0} 占位符,如前面的代码中所示。 如果 URL 模板以波形符 ~(代字号)开头,则 ~ 会替换为应用的 PathBase。 在应用中指定终结点时,请为终结点创建 MVC 视图或 Razor 页面。

使用此方法通常是当应用:

应将客户端重定向到不同的终结点(通常在不同的应用处理错误的情况下)。 对于 Web 应用,客户端的浏览器地址栏反映重定向终结点。

不应保留原始状态代码并通过初始重定向响应返回该代码。

3

站心网

异常处理程序页 若要为生产环境配置自定义错误处理页,请调用 UseExceptionHandler。 此异常处理中间件: ..

为您推荐

.NET 10 C# 14 必知的 6 大语法糖:提升开发效率,简洁优雅

.NET 10(搭配 C# 14)正式上线,带来一批令人惊喜的语法糖改进,让日常开发变得更加简洁、高效。无论你是编写企业级系统、构建性能敏感型组件,还是编写一次性脚本,这些新语法糖都能让你的代码更具可读性、减少..

2025年最佳.NET C#实现PDF转Word:主流库功能与对比

在日常工作中,将 PDF 文件高质量地转换为 Word 文档已成为许多企业和办公人员的常见需求,尤其是在文档归档、编辑流程自动化和办公系统集成等场景中尤为重要。对于使用 .NET 平台,特别是 C# 的开发者来说,选择一..

.NET Core 图像处理:Magick.NET 与 SkiaSharp 的全面对比

随着 .NET Core 的发展,传统的 System.Drawing 库因其对 Windows 的依赖性和在跨平台应用中的限制,逐渐被其他图像处理库所取代。在众多替代方案中,Magick.NET 和 SkiaSharp 是最受欢迎的两个选择。本文将从多个维..

使用.NET C#将图片转换为.ico图标文件的多种方法

在Windows应用程序开发中,图标(.ico)文件是不可或缺的一部分。本文将介绍如何使用.NET C#将常见的图片格式(如PNG、JPG、BMP)转换为.ico文件,并提供多种实现方式,包括使用System.Drawing、Magick.NET库的方法..

RevokeMsgPatcher:.NET开源、免费的Windows下PC版微信/QQ/TIM的防撤回补丁

今天给大家分享一款基于 .NET 开源、免费的适用于 Windows 下 PC 版微信/QQ/TIM的防撤回补丁(我已经看到了,撤回也没用了),通用的微信多开工具:RevokeMsgPatcher。RevokeMsgPatcher GitHub地址:https://github...

RabbitMQ 4.0+重大更新!.NET(C#)开发者必须掌握的6大升级要点

RabbitMQ 作为一款广受欢迎的消息队列中间件,近年来从 3.x 版本升级到 4.0+,带来了显著的功能增强和架构调整。与此同时,其官方 C# 客户端也从 6.x 版本跃升至 7.0,引入了全新的编程模型和性能优化。这些变化不仅..

Web前端入门第 60 问:JavaScript 各种数组定义与数组取值方法

数组可以算是程序里面最常用的数据结构了,但凡网页上任何一个列表数据,基本都是以数组的形式存在,像表格、banner图、菜单列表、商品列表,分类列表等等,在前端领域都是以数组处理。数组的定义JS 的数组花样很多..

Paylinks:基于现代 .NET 的跨平台第三方支付 SDK 详解与使用示例

Paylinks 是一套基于现代 .NET 开发的,支持跨平台、多商户的第三方支付SDK。该项目旨在简化开发者接入第三方支付平台的过程,特别是针对支付宝和微信支付,便于快速集成支付功能。Paylinks 提供了丰富的配置选项和..

Web前端入门第 53 问:JavaScript 的各种调试方法

任何一门编程语言,在学习之前都应该先弄清楚它的调试方法,毕竟没有不挖坑的人类!程序一旦出现问题,第一时间就是找到问题出在哪儿,其次才是拿出解决办法。如果都找不到问题原因,那又何从谈起解决办法呢?如何排..

.NET 使用 Qdrant.Client 连接向量数据库 Qdrant 的完整指南

随着向量数据库在 AI、搜索、推荐系统等领域的广泛应用,越来越多的开发者开始将 Qdrant 集成到自己的项目中。对于 .NET 开发者而言,使用 Qdrant.Client 实现与 Qdrant 的高效连接和数据操作,是构建语义搜索和嵌入..

Entity Framework(EF) Core 10新特性全面解析:提升开发效率的关键更新​

Entity Framework Core(EF Core)作为 .NET 平台的主流对象关系映射(ORM)框架,持续为开发者提供高效、灵活的数据访问解决方案。​在最新发布的 EF Core 10 中,微软引入了多项新特性,旨在简化数据库操作,提升..

.NET(C#)使用 iText7 高效处理PDF文件的全面指南​

在现代软件开发中,PDF 文件处理是一个常见且重要的需求。无论是生成报告、填充表单、添加水印,还是进行数字签名,选择一个功能强大的 PDF 库至关重要。iText7 作为一款开源且功能丰富的 PDF 操作库,广泛应用于 C#..

.NET Exception: Received an unexpected EOF or 0 bytes from the transport stream.解决方法

在 .NET 应用中试用HttpClient调用API异常报错“Received an unexpected EOF or 0 bytes from the transport stream,通常表示在进行 HTTPS 通信时,SSL/TLS 握手未能成功完成,导致连接被意外关闭。​以下是一..

微软退出中国对.NET开发人员有什么影响?

关于微软将停止在中国运营的报道,微软中国方面已明确表示该信息不实。网传邮件截图显示,“由于地缘政治及国际业务环境的变化,微软将调整其全球战略布局,并将于2025年4月8日起正式停止在中国区的运营”..

EasyCaching:一款灵活高效的 .NET 缓存库

EasyCaching 项目简介EasyCaching 是一个开源的 .NET 缓存抽象库,由 DotNetCore 团队开发,旨在为 .NET 应用提供简单、统一、强大且可扩展的缓存解决方案。它支持内存缓存(In-Memory)、Redis、Memcached、LiteDB..

.NET 依赖注入如何一个接口注册两种实现

在.NET的依赖注入(Dependency Injection,DI)系统中,一个接口注册两种或多种实现是常见的需求,尤其是在需要根据不同场景或条件选择不同实现时。以下是一些实现方法:1. 使用 IEnumerable<T> 解析所有实现这是最..

.NET C# 过滤从富文本编辑器html里的Javascript脚本

富文本编辑器在允许用户输入丰富内容的同时,也带来了跨站脚本攻击(XSS)的风险。过滤提交的 HTML 中的 <script> 脚本是防止跨站脚本攻击(XSS)的关键步骤。在 .NET C# 服务端过滤 <script> 脚本主要有以下几种方..

ZLinq:.NET 高性能 LINQ 替代方案及其使用指南

在 .NET 开发中,LINQ(Language Integrated Query)为数据查询提供了简洁且强大的语法。然而,传统的 LINQ 在处理大量数据时可能会引发性能瓶颈,主要由于频繁的内存分配和对象创建。为解决这一问题,Cysharp 团队..

.NET使用AutoMapper简化对象映射

在.NET软件开发中,常常需要将一个对象的数据转换并映射到另一个对象上。​这种手动映射的过程既繁琐又容易出错,影响开发效率和代码可维护性。​为了解决这一问题,AutoMapper应运而生。​什么是 AutoMapper?AutoM..

.NET C# RESTful API交互Refit库使用教程

Refit 是一个 .NET C# 库,它简化了与 RESTful API 的交互。Refit 受到 Square 的 Retrofit 库的启发,它将 REST API 转换为实时接口,允许你以声明方式定义 REST API 调用。Refit 的特点1. 声明式 API 定义:Refit ..

发表回复

返回顶部

微信分享

微信分享二维码

扫描二维码分享到微信或朋友圈

链接已复制