前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入解析 .NET Core 中的问题详情与全局异常处理:打造更优雅的 API 错误响应

深入解析 .NET Core 中的问题详情与全局异常处理:打造更优雅的 API 错误响应

作者头像
郑子铭
发布于 2025-05-08 08:14:38
发布于 2025-05-08 08:14:38
13800
代码可运行
举报
运行总次数:0
代码可运行
Image
Image

问题详情(Problem Details)简介

问题详情(Problem Details)是一种在 HTTP 响应中传递错误信息的标准方式,定义在 RFC 7807 中。标准的问题详情属性包括:

  • Type:标识问题类型的 URI
  • Title:简短的错误描述
  • Status:HTTP 状态码
  • Detail:具体的错误解释
  • Instance:标识特定错误发生的 URI

问题详情已自动集成到 .NET Core API 中。当我们返回 BadRequest 时,通常会得到包含问题详情的响应。


默认行为示例

返回 BadRequest
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 控制器方法
return BadRequest();

响应:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": ,
  "traceId": "00-2d4948694b0f223f7f5dff215b42481b-0288bb95d7604783-00"
}
返回 NotFoundException
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 控制器方法
return NotFound();

响应:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": ,
  "traceId": "00-665f3aa493eea5f307292a5862fca17e-790e01fa0f9386df-00"
}
验证错误消息
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type":"https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title":"One or more validation errors occurred.",
"status":,
"errors":{
    "Name":[
      "The Name field is required."
    ]
},
"traceId":"00-75969d38c366a25c50297e96ec3bc265-231440661829261c-00"
}

自定义问题详情

如果我们希望在 NotFound() 中传递一些消息,默认行为会有所不同。

示例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 控制器方法
return NotFound("Person not found");

响应:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Person not found

在这种情况下,响应仅包含 404 状态码和传递给 NotFound() 方法的字符串内容,而不是问题详情格式。

使用 Problem() 方法

我们可以使用 Problem() 方法来解决这个问题,从而自定义问题详情。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 请求
return Problem(
    type: "Not found exception", 
    title: "An error is occured", 
    detail: "User does not found", 
    statusCode: );

响应:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type":"Not found exception",
"title":"An error is occured",
"status":,
"detail":"User does not found",
"traceId":"00-1999d07fdaddf513f0cc4ea9244a4cd2-beb18ed447ecdb65-00"
}

添加更多详细信息

我们可以通过配置 Program 类来向问题详情响应中添加更多详细信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Program.cs
builder.Services.AddProblemDetails(options =>
{
    options.CustomizeProblemDetails = context =>
    {
        context.ProblemDetails.Instance = $"{context.HttpContext.Request.Method} {context.HttpContext.Request.Path}";
        context.ProblemDetails.Extensions.TryAdd("requestId", context.HttpContext.TraceIdentifier);
        
        var activity = context.HttpContext.Features.Get<IHttpActivityFeature>()?.Activity;
        context.ProblemDetails.Extensions.TryAdd("traceId", activity.Id);
    };
});

现在,我们的响应将如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type":"Not found exception",
"title":"An error is occured",
"status":,
"detail":"User does not found",
"instance":"GET /api/greetings",
"traceId":"00-0b258efbf453b2ab17ae347f28200faf-9f2c4c1177edb3ae-00",
"requestId":"0HN8AV48Q51I4:00000001"
}

全局异常处理

我们可以通过异常处理中间件在单一位置捕获所有异常。

自定义异常类

首先,创建用于处理 BadRequestNotFoundException 的自定义异常类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// BadRequestException.cs
publicclassBadRequestException : Exception
{
    public BadRequestException(string message):base(message)
    {
    }
}

// NotFoundException.cs
publicclassNotFoundException : Exception
{
    public NotFoundException(string message) : base(message)
    {
    }
}
创建异常处理器

创建一个名为 CustomExceptionHandler 的类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public classCustomExceptionHandler: IExceptionHandler
{
    privatereadonly IProblemDetailsService _problemDetailService;
    privatereadonly ILogger<CustomExceptionHandler> _logger;

    public CustomExceptionHandler(IProblemDetailsService problemDetailService, ILogger<CustomExceptionHandler> logger)
    {
        _problemDetailService = problemDetailService;
        _logger = logger;
    }

    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        _logger.LogError(exception.Message);

        // 根据异常确定状态码
        var (statusCode, problemDetails) = GetProblemDetailsAndStatusCode(exception);

        httpContext.Response.StatusCode = statusCode;

        returnawait _problemDetailService.TryWriteAsync(new ProblemDetailsContext {
            HttpContext = httpContext,
            ProblemDetails = problemDetails,
            Exception = exception
        });
    }

    private (int, ProblemDetails) GetProblemDetailsAndStatusCode(Exception exception)
    {
        return exception switch
        {
            BadRequestException => 
            (
                StatusCodes.Status400BadRequest,
                new ProblemDetails
                {
                    Status = StatusCodes.Status400BadRequest,
                    Title = "Bad request",
                    Detail = exception.Message,
                    Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"
                }
            ),
            NotFoundException => (
                StatusCodes.Status404NotFound,
                new ProblemDetails
                {
                    Status = StatusCodes.Status404NotFound,
                    Title = "Resource not found",
                    Detail = exception.Message,
                    Type = "https://tools.ietf.org/html/rfc7231#section-6.5.4"
                }
            ),
            _ => (
                StatusCodes.Status500InternalServerError,
                new ProblemDetails
                {
                    Status = StatusCodes.Status500InternalServerError,
                    Title = "Server error",
                    Detail = exception.Message,
                    Type = "https://tools.ietf.org/html/rfc7231#section-6.6.1"
                }
            ),
        };
    }
}
注册异常处理中间件

Program.cs 中注册异常处理中间件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Program.cs
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
app.UseExceptionHandler();

最终的 Program 类如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using Microsoft.AspNetCore.Http.Features;

var builder = WebApplication.CreateBuilder(args);

// 添加服务到容器
builder.Services.AddControllers();
builder.Services.AddOpenApi();

// 添加问题详情配置
builder.Services.AddProblemDetails(options =>
{
    options.CustomizeProblemDetails = context =>
    {
        context.ProblemDetails.Instance = $"{context.HttpContext.Request.Method} {context.HttpContext.Request.Path}";
        context.ProblemDetails.Extensions.TryAdd("requestId", context.HttpContext.TraceIdentifier);
        var activity = context.HttpContext.Features.Get<IHttpActivityFeature>()?.Activity;
        context.ProblemDetails.Extensions.TryAdd("traceId", activity.Id);
    };
});

// 注册异常处理器
builder.Services.AddExceptionHandler<CustomExceptionHandler>();

var app = builder.Build();

// 配置 HTTP 请求管道
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseExceptionHandler();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
测试自定义异常

抛出自定义异常并检查响应。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 控制器方法
throw new NotFoundException("User does not found");

响应:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "type":"https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title":"Resource not found",
"status":,
"detail":"User does not found",
"instance":"GET /api/greetings",
"traceId":"00-f4d3214afd423ad8d13d934062b283d7-f773987abae78043-00",
"requestId":"0HN8BHUP5M9SI:00000001"
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Http】一文备忘Http状态码(406,415,422)
最近在调试接口时,web api 报了一个415状态码。好久没见到这个状态码,一时还真不知道啥情况。所以,人的大脑是有遗忘规律的,为了加深印象,所以我觉得我有必要再复习一下。
DDGarfield
2022/06/23
1.7K0
【5min+】AspNet Core中的全局异常处理
【五分钟的dotnet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net知识等等。 5min+不是超过5分钟的意思,"+"是知识的增加。so,它是让您花费5分钟以下的时间来提升您的知识储备量。
句幽
2020/04/27
1.9K0
告别异常臃肿!C# Result模式实战:用.NET构建更优雅的错误处理系统
在.NET开发中,异常处理虽广泛使用,但可能带来性能损耗与代码复杂度。本文将揭秘如何通过Result模式替代异常,构建高可读、易维护且性能更优的.NET应用。
郑子铭
2025/05/21
1120
告别异常臃肿!C# Result模式实战:用.NET构建更优雅的错误处理系统
asp.net core之异常处理
在开发过程中,处理错误是一个重要的方面。ASP.NET Core提供了多种方式来处理错误,以确保应用程序的稳定性和可靠性。
饭勺oO
2023/10/18
4050
asp.net core之异常处理
ASP.NET Core 警惕可空类型开启之后模型校验失败
在开启 Nullable 可空类型之后,原本可以调用的 API 也许就会提示 400 BadRequest 因为传入参数不合法,模型校验失败,此时将不会进入预期的 API 函数,同时也不会在输出里面找到有用的信息
林德熙
2020/08/31
1.6K0
浅入ABP(2):添加基础集成服务
上一篇,我们已经搭建起了一个基本的程序结构,下面我们来添加一些必要的服务,例如异常拦截器、跨域等。
痴者工良
2021/04/26
2K0
ASP.NET CORE Study06
需要在 startup 类中的 ConfigureService 方法中进行配置 示例:
Echo_Wish
2023/11/30
1720
ASP.NET Core 错误处理(Handle Errors)
链接:cnblogs.com/xiaoxiaotank/p/15586706.html
郑子铭
2021/12/01
2.2K0
ASP.NET Core 错误处理(Handle Errors)
.net 温故知新【11】:Asp.Net Core WebAPI 入门使用及介绍
在Asp.Net Core 上面由于现在前后端分离已经是趋势,所以asp.net core MVC用的没有那么多,主要以WebApi作为学习目标。
SpringSun
2023/06/09
2.4K0
.net 温故知新【11】:Asp.Net Core WebAPI 入门使用及介绍
.NET Core开发实战(第22课:异常处理中间件:区分真异常与逻辑异常)--学习笔记(下)
接下来介绍使用代理方法的方式,也就是说把 ErrorController 整段逻辑直接定义在注册的地方,使用一个匿名委托来处理,这里的逻辑与之前的逻辑是相同的
郑子铭
2021/01/13
5180
在.NET Core 中使用 FluentValidation 进行规则验证
如果使用Web API或MVC页面,那么可能习惯了自带的规则验证,我们的控制器很干净:
全球技术精选
2021/03/03
1.8K0
在.NET Core 中使用 FluentValidation 进行规则验证
在 ASP.NET Core 中实现幂等 REST API
幂等性是 REST API 的一个关键概念,可确保系统的可靠性和一致性。幂等操作可以重复多次,而不会更改初始 API 请求之外的结果。此属性在分布式系统中尤其重要,因为网络故障或超时可能会导致重复请求。
郑子铭
2024/12/24
2310
在 ASP.NET Core 中实现幂等 REST API
ASP.NET Core错误处理中间件[3]: 异常处理器
DeveloperExceptionPageMiddleware中间件错误页面可以呈现抛出的异常和当前请求上下文的详细信息,以辅助开发人员更好地进行纠错诊断工作。ExceptionHandlerMiddleware中间件则主要面向最终用户,我们可以利用它来显示一个友好的定制化错误页面。更多关于ASP.NET Core的文章请点这里]
蒋金楠
2021/01/21
1K0
AspNetCore全局异常处理
在开发ASP.NET Core应用程序时,全局异常处理是一个重要的概念。它允许我们集中处理应用程序中未捕获的异常,确保应用程序的稳定性和用户体验。
Net分享
2024/12/11
1550
AspNetCore全局异常处理
从 MVC 到使用 ASP.NET Core 6.0 的Minimal API
https://benfoster.io/blog/mvc-to-minimal-apis-aspnet-6/
郑子铭
2021/11/10
8K0
使用 .NET Core 中的超时中间件提高 UI 性能
今天带来了 .NET Core 的新文章 Timeout 中间件,让我们了解一下,看看我们可以实时应用哪些地方。
郑子铭
2024/12/31
2430
使用 .NET Core 中的超时中间件提高 UI 性能
【ASP.NET Core 基础知识】--Web API--创建和配置Web API(二)
集成Entity Framework Core(EF Core)是在ASP.NET Core Web API中进行数据库访问的常见方式。以下是集成EF Core的基本步骤:
喵叔
2024/05/24
6500
ASP.NET Core 6框架揭秘实例演示[33]:异常处理高阶用法
NuGet包“Microsoft.AspNetCore.Diagnostics”中提供了几个与异常处理相关的中间件,我们可以利用它们将原生的或者定制的错误信息作为响应内容发送给客户端。《错误页面的N种呈现方式》演示了几个简单的实例使读者大致了解这些中间件的作用,现在我们来演示几个高阶用法。本文提供的示例演示已经同步到《ASP.NET Core 6框架揭秘-实例演示版》)
蒋金楠
2022/09/23
1.3K0
ASP.NET Core 6框架揭秘实例演示[33]:异常处理高阶用法
ASP.NET 中验证的自定义返回和统一社会信用代码的内置验证实现
DataAnnotations 命名空间提供常用的内置验证特性,可通过声明方式应用于类或属性。我们不需要编写复杂的逻辑,仅需要指定一次,即可应用到整个项目中。代码量的减少,意味着更少的出错,也更易于测试和维护。指定了验证特性的模型会进行强制执行这些验证,有助于提升应用的可靠性,同时保证你在忘记编写某些验证逻辑时,防止你通过应用提交错误的数据到数据库。下面我们来实际使用一下:
桑榆肖物
2022/11/18
1.1K0
ASP.NET 中验证的自定义返回和统一社会信用代码的内置验证实现
.NET云原生应用实践(二):Sticker微服务RESTful API的实现
毋庸置疑,Sticker微服务需要访问数据库来管理“贴纸”(也就是“Sticker”),因此,以什么方式来存储数据,就是一个无法绕开的话题。如果你遵循领域驱动设计的思想,那么你可以说,保存到数据库的数据,就是“贴纸”聚合在持久化到仓储后的一种对象状态。那现在的问题是,我们需要遵循领域驱动设计的思想吗?
郑子铭
2024/11/23
1270
.NET云原生应用实践(二):Sticker微服务RESTful API的实现
推荐阅读
相关推荐
【Http】一文备忘Http状态码(406,415,422)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验