.NET 全局异常处理:使用 IExceptionHandler 统一错误响应

前言 在前后端联调接口时,最痛苦的事情之一就是不同异常返回的格式不一致:业务异常、系统异常、模型验证错误都可能结构各异,前端处理成本高。传统做法通常是: 自定义中间件捕获异常 使用异常过滤器 (ExceptionFilter) 但这些方式存在两个问题: 某些阶段抛出的异常(例如模型绑定 / 类型转换错误)可能无法被可靠捕获; 需要手动维护额外的分层与侵入式代码。 从 .NET 8 开始,推荐的方式是使用内置的 IExceptionHandler 管道,这种方式更贴近框架设计,且更清晰集中。官方文档可参考: 处理 .NET 中的错误 - IExceptionHandler 下面演示一个统一异常处理的实际落地方案,并扩展到模型验证场景。 IExceptionHandler 的实现与示例 1. 定义统一结果模型(示例) 假设我们有一个通用的 API 返回模型: public class ApiResult { public bool Success { get; set; } public string Message { get; set; } = string.Empty; public int StatusCode { get; set; } public object? Data { get; set; } } 以及一个业务友好型异常: public class FriendlyException : Exception { public FriendlyException(string message) : base(message) { } } 2. 实现自定义异常处理器 通过实现 IExceptionHandler 接口集中处理: public class GlobalExceptionHandler : IExceptionHandler { private readonly ILogger<GlobalExceptionHandler> _logger; public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) => _logger = logger; public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception exception, CancellationToken token) { var (statusCode, message) = exception switch { FriendlyException friendly => (StatusCodes.Status400BadRequest, friendly.Message), _ => (StatusCodes.Status500InternalServerError, exception.Message) }; var apiResult = new ApiResult { Success = false, Message = message, StatusCode = statusCode }; context.Response.StatusCode = statusCode; context.Response.ContentType = "application/json; charset=utf-8"; await context.Response.WriteAsJsonAsync(apiResult, cancellationToken: token); return true; // 表示此异常已被处理 } } FriendlyException 是自定义的一个业务友好型异常类型,通过模式匹配: ...

2025-11-03 · 3 min · 478 words · yess

EF Core单独分层无法迁移

在开发个人博客项目的时候,我把EF Core单独放到了一层,也就是单独放在了xxx.Blog.EntityFrameworkCore这个类库里面。配置好Context文件后,我开始执行迁移命令 dotnet ef migrations add init 但发现抛出了异常 Unable to create a 'DbContext' of type ''. The exception 'Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[BlogDbContext]' while attempting to activate 'BlogDbContext'.' was thrown while attempting to create an instance. For the different patterns supported at design time, see <https://go.microsoft.com/fwlink/?linkid=851728> 翻译为中文就是: 无法创建类型为"的" DbContext "。异常“无法解析服务类型”Microsoft.EntityFrameworkCore。当试图激活'BlogDbContext'时,DbContextOptions ' 1[BlogDbContext]'。在尝试创建实例时抛出。有关设计时支持的不同模式,请参阅https://go.microsoft.com/fwlink/?linkid=851728 我查看了这篇文档 ,得知执行迁移命令的时候要求必须创建DbContext实例。 如果你的DbContext是在WebApi,那么你可以通过容器来创建DbContext。但是我们现在是把EF Core单独放一层,这个时候最好的方式就是用第二种方式design-time factory,也就是通过IDesignTimeDbContextFactory接口来创建DbContext。如果在与派生 DbContext 接口相同的项目或应用程序的启动项目中找到实现此接口的类,则这些工具将绕过创建 DbContext 的其他方式,而是使用design-time factory来创建。 代码如下: public class BlogDesignTimeDbContextFactory : IDesignTimeDbContextFactory<BlogDbContext> { public BlogDbContext CreateDbContext(string[] args) { DbContextOptionsBuilder<BlogDbContext> builder = new(); var configuration=new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); var connStr=configuration.GetConnectionString("BlogDataConnect"); throw new ArgumentNullException("没有找到连接字符串"); builder.UseSqlServer(connStr); return new BlogDbContext(builder.Options, null); } } 这上面有两个注意的点: ...

2024-05-02 · 1 min · 123 words · yess