You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AspNetCore 7/8自定义异常处理器结合ProblemDetails时XML失效排查

问题:AspNetCore 7/8自定义异常处理器下ProblemDetails XML格式返回空

现象描述

将API升级到AspNetCore 7/8后,使用默认的app.UseExceptionHandler();时,Accept: application/json和Accept: application/xml格式的异常响应都能正常返回符合RFC7807的ProblemDetails内容。

测试请求示例:

curl https://localhost:7089/Test -H "Accept: application/json" 

返回:

{
    "type": "https://tools.ietf.org/html/rfc9110#section-15.6.1",
    "title": "An error occurred while processing your request.",
    "status": 500,
    "traceId": "00-7165c3ae88dba50c1c055a15f2bcf893-79d5c49179a9b30c-00"
}
curl https://localhost:7089/Test -H "Accept: application/xml"

返回:

<problem xmlns="urn:ietf:rfc:7807">
    <status>500</status>
    <title>An error occurred while processing your request.</title>
    <type>https://tools.ietf.org/html/rfc9110#section-15.6.1</type>
    <traceId>00-d8cf6db0704770b8badf2376da7c4f4c-4d6ead3e06d28c25-00</traceId>
</problem>

但按照官方文档示例添加自定义异常处理器后:

app.UseExceptionHandler(x => x.Run(async context =>
{
    if (context.Response.HasStarted)
        return;

    var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error;
    if (exception == null)
        throw new Exception("ExceptionHandler without exception!");

    var problemDetailsService = context.RequestServices.GetService<IProblemDetailsService>();
    await problemDetailsService.WriteAsync(new ProblemDetailsContext
    {
        HttpContext = context,
        ProblemDetails =
        {
            Title = exception.Message,
        }
    });
}));

JSON格式响应正常,但XML格式返回空内容:

curl https://localhost:7089/Test -H "Accept: application/json" 

返回:

{
    "type": "https://tools.ietf.org/html/rfc9110#section-15.6.1",
    "title": "message from exception",
    "status": 500
}
curl https://localhost:7089/Test -H "Accept: application/xml"

无返回内容,日志中出现异常:

Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware: Error: An exception was thrown attempting to execute the error handler.

System.InvalidOperationException: Unable to find a registered IProblemDetailsWriter that can write to the given context.

at Microsoft.AspNetCore.Http.ProblemDetailsService.WriteAsync(ProblemDetailsContext context)

原因分析

默认的ExceptionHandlerMiddleware内部会借助MVC的格式化系统(包括通过AddXmlSerializerFormatters()注册的XML格式化器)来处理响应序列化,但自定义异常处理器直接调用IProblemDetailsService.WriteAsync()时,DI容器中默认只注册了JSON格式的IProblemDetailsWriter实现,XML对应的Writer并没有被自动注册——AddXmlSerializerFormatters()仅配置了MVC的XML格式化器,并未关联到IProblemDetailsService的写入器体系。

解决方案

方案1:注册内置的XmlProblemDetailsWriter(推荐)

AspNetCore内置了XmlProblemDetailsWriter,只需手动将其注册到DI容器即可:

using Microsoft.AspNetCore.Mvc.Formatters.Xml; // 需要添加此命名空间

var builder = WebApplication.CreateBuilder(args);

// 添加Controllers并启用XML格式化器
builder.Services.AddControllers().AddXmlSerializerFormatters();
// 注册XML格式的ProblemDetails写入器
builder.Services.AddTransient<IProblemDetailsWriter, XmlProblemDetailsWriter>();
builder.Services.AddProblemDetails();

// 后续代码不变...

方案2:利用MVC的ObjectResult处理格式化

如果不想额外注册Writer,可以在自定义异常处理器中直接使用MVC的格式化系统,通过ObjectResultExecutor来处理ProblemDetails的序列化:

app.UseExceptionHandler(x => x.Run(async context =>
{
    if (context.Response.HasStarted)
        return;

    var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error;
    if (exception == null)
        throw new InvalidOperationException("ExceptionHandler without exception!");

    // 构建自定义ProblemDetails
    var problemDetails = new ProblemDetails
    {
        Title = exception.Message,
        Status = StatusCodes.Status500InternalServerError,
        Type = "https://tools.ietf.org/html/rfc9110#section-15.6.1",
        Extensions = { ["traceId"] = context.TraceIdentifier }
    };

    // 获取MVC的ObjectResult执行器,复用已配置的格式化器
    var executor = context.RequestServices.GetRequiredService<ObjectResultExecutor>();
    var result = new ObjectResult(problemDetails)
    {
        StatusCode = problemDetails.Status
    };

    await executor.ExecuteAsync(new ActionContext(context, context.GetRouteData(), new ControllerActionDescriptor()), result);
}));

验证结果

修改后重新发送XML格式请求,会返回符合RFC7807规范的XML响应:

<problem xmlns="urn:ietf:rfc:7807">
    <status>500</status>
    <title>This is a test exception</title>
    <type>https://tools.ietf.org/html/rfc9110#section-15.6.1</type>
    <traceId>00-xxxxxx-xxxxxx-00</traceId>
</problem>

内容的提问来源于stack exchange,提问作者adrianm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:27:03