ASP.NETCore-中间件Middleware(二)_全局异常_Net7
一、ASP.NETCore提供的记录全局异常的几种方式
1、MVC框架-异常处理页(开发环境/生产环境)
1)开发环境
使用app.UseDeveloperExceptionPage()启用“异常处理页”;异常处理页显示真实的报错信息不可轻易让用户看到,一般在开发环境中使用。
builder.Services.AddControllers(); // 使用控制器
builder.Services.AddMvc(); // 使用MVC
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage(); // MVC开发环境下的异常处理页;WebAPI中不需要用,只使用SwaggerUI即可。
}
...
app.MapControllers();
app.Run();
2)生产环境
使用app.UseExceptionHandler("/error")自定义“异常处理页”;一般用在生产环境中。
builder.Services.AddControllers(); // 使用控制器
builder.Services.AddMvc(); // 使用MVC
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) // 开发环境下
{
app.UseDeveloperExceptionPage(); // MVC开发环境下的异常处理页;WebAPI中不需要用,只使用SwaggerUI即可。
}
else // IsProduction、IsStaging等环境下
{
app.UseExceptionHandler("/error"); // MVC开发环境下的自定义的异常处理页(页面为/error);保证返回信息中不包含敏感信息;WebAPI中不需要用,使用异常中间件即可。
}
...
app.MapControllers();
app.Run();
MVC视图(error)
@model fly_chat1_net7.Exceptions.IKnownException_UseExceptionHandler
@{
ViewData["Title"] = "Index";
}
<h1>错误信息</h1>
<div>发生错误的时间:<label>@Model.ErrorDateTime</label></div>
<!-- 错误信息也可以作为敏感信息,不做展示 -->
<div>错误信息:<label>@Model.ErrorMessage</label></div>
<div>错误代码:<label>@Model.ErrorCode</label></div>
MVC控制器(error)
using fly_chat1_net7.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace fly_chat1_net7.Controllers
{
/// <summary>
/// MVC展示用户自定义异常信息页(KnownException_UseExceptionHandler)
/// </summary>
[AllowAnonymous]
public class ErrorController : Controller
{
/// <summary>
/// MVC展示用户自定义异常信息页(KnownException_UseExceptionHandler)
/// </summary>
/// <returns>返回用户自定义的Error信息</returns>
[Route("/error")]
public IActionResult Index()
{
// 获取当前上下文里面报出的异常信息
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
var ex = exceptionHandlerPathFeature?.Error;
// 特殊处理,尝试转换为 IKnownException
var knownException = ex as IKnownException_UseExceptionHandler;
// 对于未知异常,我们并不应该把错误异常完整地输出给客户端,而是应该定义一个特殊的信息 Unknown 传递给用户
// Unknown 其实也是一个 IKnownException 的实现,它的 Message = "未知错误", ErrorCode = 9999
// 也就是说我们在控制器 throw new Exception("报个错"); 就会看到错误信息
if (knownException == null)
{
knownException = KnownException_UseExceptionHandler.UnKnownException;
}
else// 当识别到异常是已知的业务异常时,输出已知的异常,包括异常消息,错误状态码和错误信息,就是在 IKnownException 中的定义
{
knownException = KnownException_UseExceptionHandler.SetKnownException(knownException);
}
return View(knownException);
}
}
}
MVC实体(error)
namespace fly_chat1_net7.Exceptions
{
/// <summary>
/// 自定义异常处理页接口_UseExceptionHandler
/// </summary>
public interface IKnownException_UseExceptionHandler
{
/// <summary>
/// 异常发生的时间
/// </summary>
public DateTime ErrorDateTime { get; }
/// <summary>
/// 异常信息(错误信息也可以作为敏感信息,不做展示)
/// </summary>
public string ErrorMessage { get; }
/// <summary>
/// 异常代码
/// </summary>
public int ErrorCode { get; }
/// <summary>
/// 异常对象
/// </summary>
public object[] ErrorData { get; }
}
/// <summary>
/// 自定义异常处理页_UseExceptionHandler
/// </summary>
public class KnownException_UseExceptionHandler : IKnownException_UseExceptionHandler
{
#region 变量
/// <summary>
/// 异常发生的时间
/// </summary>
public DateTime ErrorDateTime { get; private set; }
/// <summary>
/// 异常信息
/// </summary>
public string ErrorMessage { get; private set; }
/// <summary>
/// 异常代码
/// </summary>
public int ErrorCode { get; private set; }
/// <summary>
/// 异常对象
/// </summary>
public object[] ErrorData { get; private set; }
#endregion 变量
/// <summary>
/// 未知错误信息实体
/// </summary>
public readonly static IKnownException_UseExceptionHandler UnKnownException = new KnownException_UseExceptionHandler { ErrorDateTime = DateTime.Now, ErrorMessage = "未知错误", ErrorCode = 9999, ErrorData = null };
/// <summary>
/// 设置“自定义异常处理页”的内容
/// </summary>
/// <param name="exception">“自定义异常处理页”的内容</param>
/// <returns></returns>
public static IKnownException_UseExceptionHandler SetKnownException(IKnownException_UseExceptionHandler exception)
{
return new KnownException_UseExceptionHandler { ErrorDateTime = exception.ErrorDateTime, ErrorMessage = exception.ErrorMessage, ErrorCode = exception.ErrorCode, ErrorData = exception.ErrorData };
}
}
}
效果类似于下图:
2、异常过滤器 IExceptionFilter
实现 IExceptionFilter 或 IAsyncExceptionFilter,
可用于实现常见的错误处理策略(如:处理 Razor 页面或控制器创建、模型绑定、操作筛选器或操作方法中发生的未经处理的异常)。但是,请不要捕获资源筛选器、结果筛选器或 MVC 结果执行中发生的异常。
非常适合捕获发生在操作中的异常;并不像错误处理中间件(ExceptionFilterAttribute)那么灵活。
1)实现IExceptionFilter
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace fly_chat1_net7.Middlewares
{
/// <summary>
/// 异常过滤器(筛选器)
/// 可用于实现常见的错误处理策略(如:处理 Razor 页面或控制器创建、模型绑定、操作筛选器或操作方法中发生的未经处理的异常)。
/// 但是,请不要捕获资源筛选器、结果筛选器或 MVC 结果执行中发生的异常。
/// 建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
/// </summary>
public class SampleExceptionFilter : IExceptionFilter
{
#region 微软官方示例
//private readonly IHostEnvironment _hostEnvironment;
//public SampleExceptionFilter(IHostEnvironment hostEnvironment) =>
// _hostEnvironment = hostEnvironment;
//public void OnException(ExceptionContext context)
//{
// if (!_hostEnvironment.IsDevelopment())
// {
// // Don't display exception details unless running in Development.
// return;
// }
// context.Result = new ContentResult
// {
// Content = context.Exception.ToString()
// };
//}
#endregion 微软官方示例
/// <summary>
/// 实现OnException方法
/// </summary>
/// <param name="context">异常内容</param>
public void OnException(ExceptionContext context)
{
if (context.ExceptionHandled == false) // 如果异常没有被处理则进行处理
{
// 写自己的记录日志的方法
//_loggerHelper.Error(context.HttpContext.Request.Path, context.Exception);
context.Result = new ContentResult
{
// 返回状态码设置为200,表示成功
StatusCode = StatusCodes.Status200OK,
ContentType = "application/json;charset=utf-8", // 设置返回格式
Content = $"{{\r\n \"Code\": 500,\r\n \"Message\": \"{context.Exception.ToString()}\"\r\n}}\r\n"
};
}
context.ExceptionHandled = true; // 设置为true,表示异常已经被处理了
}
}
}
2)注册全局使用
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); // 添加Controller
builder.Services.AddSingleton(new SampleExceptionFilter()); // 添加异常过滤器
3)WebAPI测试:
#region WebAPI测试
/// <summary>
/// 异常处理测试API
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult ErrorShow()
{
throw new Exception("异常处理测试");
}
#endregion WebAPI测试
3、异常属性标识 ExceptionFilterAttribute(推荐)
ExceptionFilterAttribute
继承IExceptionFilter
。但可以获取比IExceptionFilter
更多的异常。建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
1)重写ExceptionFilterAttribute的OnException方法
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
namespace fly_chat1_net7.Middlewares
{
/// <summary>
/// 全局异常中间件(使用ExceptionFilterAttribute属性标识)
/// ExceptionFilterAttribute继承IExceptionFilter。但可以获取比IExceptionFilter更多的异常。建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
/// </summary>
public class MyExceptionFilter: ExceptionFilterAttribute
{
/// <summary>
/// 重写OnException方法
/// </summary>
/// <param name="context"></param>
public override void OnException(ExceptionContext context)
{
if (context.ExceptionHandled == false) // 如果异常没有被处理则进行处理
{
// 写入日志
//_loggerHelper.Error(context.HttpContext.Request.Path, context.Exception);
context.Result = new ContentResult
{
// 返回状态码设置为200,表示成功
StatusCode = StatusCodes.Status200OK,
ContentType = "application/json;charset=utf-8", // 设置返回格式
Content = $"{{\r\n \"Code\": 500,\r\n \"Message\": \"{context.Exception.ToString()}\"\r\n}}\r\n"
};
}
context.ExceptionHandled = true; // 设置为true,表示异常已经被处理了
}
}
}
2)注册全局使用
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); // 添加Controller
builder.Services.AddSingleton(new MyExceptionFilter()); // 添加全局异常中间件
3)WebAPI测试:
#region WebAPI测试
/// <summary>
/// 异常处理测试API
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult ErrorShow()
{
throw new Exception("异常处理测试");
}
#endregion WebAPI测试
4、异常处理-UseExceptionHandler()+委托方法(不推荐)
略
本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/articles/17410589.html
分类:
ASP.NETCore-中间件
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
2022-05-17 VS报错-无法解析位于global.json 中指定的 .NET SDK 版本