.NET 5添加自定义Output Formatter后如何保留默认输出格式化器
我明白你的困扰——现在不管请求的Accept头设置成什么,接口都会返回Excel格式,而你希望默认返回JSON,只有当Accept头指定为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet时才触发自定义的Excel格式化器。
问题根源
当你直接给单个ObjectResult添加自定义格式化器时,ObjectResult的Formatters集合会被你添加的内容覆盖(原本是空集合),不会自动继承全局配置的默认JSON格式化器。所以此时只有你添加的ExcelOutputFormatter可用,自然不管什么Accept头都返回Excel。
解决方案1:给单个ObjectResult添加默认JSON格式化器
如果你只需要在特定Action中启用Excel输出,可以手动把默认的JSON格式化器加入到ObjectResult的Formatters集合中。.NET 5默认使用SystemTextJsonOutputFormatter作为JSON格式化器,你可以通过依赖注入获取默认的JSON配置来创建它:
首先在控制器构造函数中注入IOptions<JsonOptions>:
private readonly IOptions<JsonOptions> _jsonOptions; public YourController(IOptions<JsonOptions> jsonOptions) { _jsonOptions = jsonOptions; }
然后修改Action中的代码:
var result = new ObjectResult(list) { StatusCode = (int)HttpStatusCode.OK }; // 添加默认的JSON格式化器(使用全局配置) result.Formatters.Add(new SystemTextJsonOutputFormatter(_jsonOptions.Value.JsonSerializerOptions)); // 添加自定义Excel格式化器 result.Formatters.Add(new ExcelOutputFormatter()); return result;
这样ASP.NET Core的内容协商机制就会正常工作:
- 当
Accept头为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet时,使用ExcelOutputFormatter - 当
Accept头为application/json或*/*时,使用默认的JSON格式化器
解决方案2:全局配置自定义格式化器(更优雅)
如果你的多个Action都需要支持Excel输出,推荐在全局配置中添加自定义格式化器,这样默认的JSON格式化器会被保留,不需要在每个Action中手动添加:
在Startup.cs的ConfigureServices方法中:
services.AddControllers(options => { // 添加自定义Excel格式化器,全局生效 options.OutputFormatters.Add(new ExcelOutputFormatter()); });
之后在Action中只需要正常返回ObjectResult即可,不需要手动添加格式化器:
return new ObjectResult(list) { StatusCode = (int)HttpStatusCode.OK };
这种方式下,全局格式化器集合包含默认的JSON格式化器和你的自定义Excel格式化器,内容协商会自动根据Accept头选择合适的输出格式。
额外检查
确保你的ExcelOutputFormatter中的SupportedMediaTypes配置正确,你当前的代码已经做了这一步:
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
这是内容协商能正确匹配的关键。
内容的提问来源于stack exchange,提问作者Tundy

