如何全局配置.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
相关产品推荐
相关产品推荐

