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

如何全局配置.NET Minimal API以XML响应?含路由组及错误响应

为ASP.NET Core Minimal API全局配置XML/HTML输出(路由、路由组及错误响应)

如果已经掌握单个端点通过IResult和IResultExtensions返回XML/HTML的方法,要实现全局覆盖所有路由、路由组及错误响应,可通过以下步骤完成:


1. 全局注册输出格式化器

首先在Program.cs中配置服务,添加XML和HTML的输出格式化器,让所有端点的响应能自动根据请求的Accept头适配格式:

builder.Services.AddControllers(options =>
{
    // 注册XML序列化输出格式化器
    options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
    
    // 注册HTML格式化器(示例用StringOutputFormatter,若需渲染Razor视图可扩展)
    options.OutputFormatters.Add(new StringOutputFormatter("text/html"));
});

// 确保Minimal API能利用这些格式化器
builder.Services.AddEndpointsApiExplorer();

配置后,所有端点返回的IResult(如Results.Ok、Results.BadRequest等)都会自动识别Accept头并返回对应格式。


2. 路由组统一格式支持

为避免在每个端点重复声明支持的格式,可创建扩展方法为整个路由组批量配置:

public static class RouteGroupExtensions
{
    public static RouteGroupBuilder EnableXmlAndHtmlSupport(this RouteGroupBuilder group)
    {
        group.WithMetadata(new ProducesResponseTypeMetadata(
            StatusCodes.Status200OK, 
            "application/json", 
            "application/xml", 
            "text/html"));
        return group;
    }
}

使用时只需在路由组上调用该方法,组内所有端点自动继承格式支持:

var apiGroup = app.MapGroup("/api").EnableXmlAndHtmlSupport();
apiGroup.MapGet("/users", () => Results.Ok(User.GetSampleUsers()));
apiGroup.MapGet("/products", () => Results.Ok(Product.GetSampleProducts()));

3. 错误响应的格式适配

要让404、500等错误响应也遵循XML/HTML格式,需自定义异常处理和状态码页面:

自定义异常处理(处理服务器内部错误)

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        var errorMsg = exceptionFeature?.Error?.Message ?? "An unexpected error occurred.";
        var statusCode = StatusCodes.Status500InternalServerError;

        // 根据Accept头确定响应格式
        var acceptHeader = context.Request.Headers.Accept.ToString();
        context.Response.ContentType = acceptHeader.Contains("application/xml") 
            ? "application/xml" 
            : acceptHeader.Contains("text/html") 
                ? "text/html" 
                : "application/json";
        context.Response.StatusCode = statusCode;

        var errorResponse = new ErrorResponse
        {
            StatusCode = statusCode,
            Message = errorMsg,
            Path = exceptionFeature?.Path
        };

        switch (context.Response.ContentType)
        {
            case "application/xml":
                var xmlSerializer = new XmlSerializer(typeof(ErrorResponse));
                await xmlSerializer.SerializeAsync(context.Response.Body, errorResponse);
                break;
            case "text/html":
                var html = $"<html><body><h1>Error {statusCode}</h1><p>{errorMsg}</p><p>Path: {exceptionFeature?.Path}</p></body></html>";
                await context.Response.WriteAsync(html);
                break;
            default:
                await context.Response.WriteAsJsonAsync(errorResponse);
                break;
        }
    });
});

自定义状态码页面(处理404、401等非异常错误)

app.UseStatusCodePages(async context =>
{
    var response = context.HttpContext.Response;
    var acceptHeader = context.HttpContext.Request.Headers.Accept.ToString();
    
    response.ContentType = acceptHeader.Contains("application/xml") 
        ? "application/xml" 
        : acceptHeader.Contains("text/html") 
            ? "text/html" 
            : "application/json";

    var msg = response.StatusCode switch
    {
        404 => "Requested resource not found.",
        401 => "Unauthorized access. Please authenticate.",
        _ => $"Status code {response.StatusCode} encountered."
    };

    var statusResponse = new StatusCodeResponse
    {
        StatusCode = response.StatusCode,
        Message = msg
    };

    switch (response.ContentType)
    {
        case "application/xml":
            var xmlSerializer = new XmlSerializer(typeof(StatusCodeResponse));
            await xmlSerializer.SerializeAsync(response.Body, statusResponse);
            break;
        case "text/html":
            var html = $"<html><body><h1>Status {response.StatusCode}</h1><p>{msg}</p></body></html>";
            await response.WriteAsync(html);
            break;
        default:
            await response.WriteAsJsonAsync(statusResponse);
            break;
    }
});

辅助类定义

需要创建对应的响应模型类用于序列化:

public class ErrorResponse
{
    public int StatusCode { get; set; }
    public string Message { get; set; }
    public string Path { get; set; }
}

public class StatusCodeResponse
{
    public int StatusCode { get; set; }
    public string Message { get; set; }
}

4. 验证方式

发送请求时设置Accept头即可获取对应格式的响应:

  • Accept: application/xml:返回XML格式
  • Accept: text/html:返回HTML格式
  • Accept: application/json:返回默认JSON格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:25:26