当前位置: 首页 > news >正文

【连载7】 C# MVC 跨框架异常处理对比:.NET Framework 与 .NET Core 实现差异

异常处理是任何应用程序的关键部分,尤其在 MVC 架构中,统一的异常处理机制能极大提升代码可维护性。下面通过代码示例对比 .NET Framework 与 .NET Core 在 MVC 异常处理上的实现差异

1. 全局异常处理实现

迁移到 .NET Core 的异常处理挑战

从 .NET Framework 迁移到 .NET Core 时,异常处理机制的差异可能带来以下挑战:

HTTP 管道差异
在 .NET Framework 中,Global.asaxHttpApplicationApplication_Error 是全局异常处理的主要方式。而 .NET Core 采用中间件(Middleware)模式,需使用 UseExceptionHandler 或自定义中间件捕获异常,迁移时需调整代码结构。

异步代码支持
.NET Core 更强调异步编程,未处理的异步异常可能导致进程崩溃。需确保 async/await 方法中异常被正确捕获,或通过 TaskScheduler.UnobservedTaskException 处理未观察的任务异常。

依赖注入集成
.NET Core 内置 DI 容器,异常处理中间件可能依赖注入的服务。需在中间件中正确解析服务,例如通过构造函数注入或 HttpContext.RequestServices

日志记录变化
.NET Framework 中常用 System.Diagnostics.Trace 或第三方日志库,而 .NET Core 推荐使用 ILogger 接口。迁移时需重构日志记录逻辑,确保异常信息被正确输出到控制台、文件或第三方平台(如 Serilog)。

其他关键差异点

Kestrel 与 IIS 集成
.NET Core 默认使用 Kestrel 作为 Web 服务器,异常处理行为可能与 IIS 不同。例如,Kestrel 对请求超时或连接中断的响应方式需特别配置。

配置文件转换
web.configappsettings.json 替代,异常处理相关的配置(如自定义错误页面路径)需迁移到新格式,并通过代码加载。

跨平台兼容性
.NET Core 运行在 Linux/macOS 时,某些 Windows 特定的异常(如 COM 组件调用)可能不适用,需替换为跨平台方案或条件编译。

欢迎在评论区补充你的迁移经验,例如如何解决特定异常类型兼容性问题,或优化中间件性能的实践!

.NET Framework 实现方式

在 .NET Framework 中,全局异常处理通常通过自定义 HandleErrorAttribute 和全局过滤器实现。以下是实现步骤:

创建自定义异常处理特性类 CustomHandleErrorAttribute,继承自 HandleErrorAttribute

public class CustomHandleErrorAttribute : HandleErrorAttribute
{public override void OnException(ExceptionContext filterContext){if (filterContext.ExceptionHandled)return;var exception = filterContext.Exception;LogException(exception);if (filterContext.HttpContext.Request.IsAjaxRequest()){filterContext.Result = new JsonResult{Data = new { success = false, error = exception.Message },JsonRequestBehavior = JsonRequestBehavior.AllowGet};}else{filterContext.Result = new ViewResult{ViewName = "Error",ViewData = new ViewDataDictionary(exception)};}filterContext.ExceptionHandled = true;}private void LogException(Exception ex){// 日志记录逻辑}
}

FilterConfig 类中注册全局过滤器:

public class FilterConfig
{public static void RegisterGlobalFilters(GlobalFilterCollection filters){filters.Add(new CustomHandleErrorAttribute());}
}

Global.asaxApplication_Start 方法中调用过滤器注册:

protected void Application_Start()
{FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}

.NET Core 实现方式

在 .NET Core 中,全局异常处理通常通过自定义中间件实现。以下是实现步骤:

创建异常处理中间件类 ExceptionMiddleware

public class ExceptionMiddleware
{private readonly RequestDelegate _next;private readonly ILogger<ExceptionMiddleware> _logger;public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext httpContext){try{await _next(httpContext);}catch (Exception ex){_logger.LogError(ex, "发生未处理的异常");await HandleExceptionAsync(httpContext, ex);}}private async Task HandleExceptionAsync(HttpContext context, Exception exception){context.Response.ContentType = "application/json";context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;var response = new{statusCode = context.Response.StatusCode,message = "发生内部服务器错误",detailed = exception.Message};var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };var json = JsonSerializer.Serialize(response, options);await context.Response.WriteAsync(json);}
}

Program.cs 中配置中间件:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();var app = builder.Build();if (app.Environment.IsDevelopment())
{app.UseDeveloperExceptionPage();
}
else
{app.UseMiddleware<ExceptionMiddleware>();app.UseHsts();
}app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");app.Run();

日志记录建议

在异常处理中,日志记录是重要环节。建议使用现有的日志框架:

在 .NET Framework 中使用 NLog:

private static readonly Logger Logger = LogManager.GetCurrentClassLogger();private void LogException(Exception ex)
{Logger.Error(ex, "发生未处理的异常");
}

在 .NET Core 中使用内置的 ILogger:

_logger.LogError(ex, "发生未处理的异常");

生产环境注意事项

对于生产环境,应避免向客户端返回详细的异常信息。可以修改中间件以返回通用错误信息:

var response = new
{statusCode = context.Response.StatusCode,message = "发生内部服务器错误",detailed = app.Environment.IsDevelopment() ? exception.Message : null
};

2. 常见的 “坑” 及解决方案

坑 1:异常处理范围不完整

在.NET Core中,全局异常处理可以通过中间件实现,覆盖整个请求管道的异常,包括路由、身份验证等阶段。以下为具体方法:

自定义异常处理中间件
创建中间件捕获所有异常并统一处理:

public class ExceptionMiddleware
{private readonly RequestDelegate _next;public ExceptionMiddleware(RequestDelegate next) => _next = next;public async Task InvokeAsync(HttpContext context){try { await _next(context); }catch (Exception ex){context.Response.StatusCode = StatusCodes.Status500InternalServerError;await context.Response.WriteAsync("全局异常处理: " + ex.Message);}}
}

注册到Startup.cs

app.UseMiddleware<ExceptionMiddleware>();

内置异常处理中间件
直接使用.NET Core提供的UseExceptionHandler

app.UseExceptionHandler("/Error"); // 指定错误路由
app.UseStatusCodePagesWithReExecute("/Error/{0}"); // 处理404等状态码

对比旧版Framework方案
相比传统ASP.NET MVC的HandleErrorAttribute,中间件方案的优势在于:

  • 可处理中间件管道中任何阶段的异常
  • 能捕获静态文件处理、身份验证等非控制器逻辑的异常
  • 支持自定义响应格式(JSON/HTML等)

进阶建议

  • 生产环境区分开发/生产错误页(UseDeveloperExceptionPage
  • 结合日志系统(如Serilog)记录异常上下文
  • 对API项目可返回标准化错误JSON格式

坑 2:开发 / 生产环境配置混淆

在开发环境中需要显示详细错误信息以便于调试,但在生产环境中需要隐藏这些信息以避免安全隐患。使用条件判断确保不同环境采用不同的异常处理策略。

if (app.Environment.IsDevelopment())
{app.UseDeveloperExceptionPage();
}
else
{app.UseMiddleware<ExceptionMiddleware>();app.UseHsts();
}

坑 3:异常被多次处理

在 .NET Framework 中,同时使用 HandleErrorAttributeApplication_Error 事件可能导致异常被重复处理。应选择一种全局异常处理机制,并正确设置 ExceptionHandled = true 以避免重复处理。

坑 4:异步代码中的异常丢失

早期版本的 .NET Framework 在处理异步控制器方法时可能存在异常捕获不完整的问题。升级至最新版本或迁移到 .NET Core 可以解决这一问题,后者对异步代码的异常处理机制更加完善。

坑 5:日志记录不完整

仅记录异常消息而不记录堆栈跟踪或请求信息会导致调试困难。应采用完整的日志记录方式,包含异常对象、请求方法和路径等关键信息。

_logger.LogError(ex, "异常发生在请求 {Method} {Path}", context.Request.Method, context.Request.Path);

3.讨论

迁移到 .NET Core 的异常处理挑战

从 .NET Framework 迁移到 .NET Core 时,异常处理机制的差异可能带来以下挑战:

HTTP 管道差异
在 .NET Framework 中,Global.asaxHttpApplicationApplication_Error 是全局异常处理的主要方式。而 .NET Core 采用中间件(Middleware)模式,需使用 UseExceptionHandler 或自定义中间件捕获异常,迁移时需调整代码结构。

异步代码支持
.NET Core 更强调异步编程,未处理的异步异常可能导致进程崩溃。需确保 async/await 方法中异常被正确捕获,或通过 TaskScheduler.UnobservedTaskException 处理未观察的任务异常。

依赖注入集成
.NET Core 内置 DI 容器,异常处理中间件可能依赖注入的服务。需在中间件中正确解析服务,例如通过构造函数注入或 HttpContext.RequestServices

日志记录变化
.NET Framework 中常用 System.Diagnostics.Trace 或第三方日志库,而 .NET Core 推荐使用 ILogger 接口。迁移时需重构日志记录逻辑,确保异常信息被正确输出到控制台、文件或第三方平台(如 Serilog)。

其他关键差异点

Kestrel 与 IIS 集成
.NET Core 默认使用 Kestrel 作为 Web 服务器,异常处理行为可能与 IIS 不同。例如,Kestrel 对请求超时或连接中断的响应方式需特别配置。

配置文件转换
web.configappsettings.json 替代,异常处理相关的配置(如自定义错误页面路径)需迁移到新格式,并通过代码加载。

跨平台兼容性
.NET Core 运行在 Linux/macOS 时,某些 Windows 特定的异常(如 COM 组件调用)可能不适用,需替换为跨平台方案或条件编译。

欢迎在评论区补充你的迁移经验,例如如何解决特定异常类型兼容性问题,或优化中间件性能的实践!

http://www.dtcms.com/a/393568.html

相关文章:

  • 芯脉:面向高速接口的SoC架构与完整性设计<3>
  • ArrayList与LinkedList深度对比
  • AI IDE 综合评估:代码能力与上下文连续性深度分析
  • OceanBase备租户创建(一):通过CREATE STANDBY TENANT
  • C++ 多态:从概念到实践,吃透面向对象核心特性
  • ​​如何用 Webpack 或 Vite 给文件名(如 JS、CSS、图片等静态资源)加 Hash?这样做有什么好处?​​
  • QT-数据库编程
  • FastAPI + APScheduler + Uvicorn 多进程下避免重复加载任务的解决方案
  • 数据库造神计划第十八天---事务(1)
  • Docker在Linux中离线部署
  • 面阵vs线阵工业相机的触发方式有什么不同?
  • 【Hadoop】HBase:构建于HDFS之上的分布式列式NoSQL数据库
  • 拉取GitHub源码方式
  • 【国二】【C语言】改错题中考察switch的用法、do while执行条件的用法
  • 23种设计模式之【命令模式模式】-核心原理与 Java 实践
  • APP持续盈利:简单可行实行方案
  • qt 操作pdf文档小工具
  • Web3 开发者周刊 68 | EF 将成立一个新的 AI 团队
  • [OpenGL]相机系统
  • 软件体系结构——负载均衡
  • Unity 游戏引擎中 HDRP(高清渲染管线) 的材质着色器选择列表
  • 系统架构设计师(现代计算机系统架构和软件开发)错题集
  • 七、Linux创建自己的proc文件
  • 理解CSS中的100%和100vh
  • [特殊字符] Chrome浏览器证书导入指南
  • 15-用户登录案例
  • Kurt-Blender零基础教程:第3章:材质篇——第1节:材质基础~原理化BSDF,添加有纹理材质与用蒙版做纹理叠加
  • 南京大学 - 复杂结构数据挖掘(一)
  • 嵌入式系统、手机与电脑:一场技术演化的“三角关系”
  • Go语言常用的第三方开发包教程合集