设置 ASP.NET Core Web API 中响应数据的格式
作者:Rick Anderson 和 Steve Smith
ASP.NET Core MVC 支持设置响应数据的格式。 可以使用特定格式或响应客户端请求的格式,来设置响应数据的格式。
特定于格式的操作结果
一些操作结果类型特定于特殊格式,例如 JsonResult 和 ContentResult。 操作可以返回使用特定格式设置格式的结果,而不考虑客户端首选项。 例如,返回 JsonResult
,将返回 JSON 格式的数据。 返回 ContentResult
或字符串,将返回纯文本格式的字符串数据。
无需操作返回任意特定类型。 ASP.NET Core 支持任何对象返回值。 返回非 IActionResult 类型对象的操作结果将使用相应的 IOutputFormatter 实现来进行序列化。 有关详细信息,请参阅 ASP.NET Core Web API 中控制器操作的返回类型。
内置的帮助程序方法 Ok 返回 JSON 格式的数据:[!code-csharp]
示例下载返回作者列表。 在 F12 浏览器开发人员工具或 Postman 中使用上述代码:
- 将显示包含内容类型的响应标头。
application/json; charset=utf-8
- 将显示请求标头。 例如
Accept
标头。 上述代码将忽略Accept
标头。
若要返回纯文本格式数据,请使用 Content 和 Content 帮助程序:
// GET api/authors/about [HttpGet("About")] public ContentResult About() { return Content("An API listing authors of docs.asp.net."); }
在上述代码中,返回的 text/plain
为 Content-Type
。 返回字符串,将提供 text/plain
类型的 Content-Type
:
// GET api/authors/version [HttpGet("version")] public string Version() { return "Version 1.0.0"; }
对于包含多个返回类型的操作,将返回 IActionResult
。 例如,基于执行的操作的结果返回不同的 HTTP 状态代码。
内容协商
当客户端指定 Accept 标头时,会发生内容协商。 ASP.NET Core 使用的默认格式是 JSON。 内容协商有以下特点:
- 由 ObjectResult 实现。
- 内置于从帮助程序方法返回的特定于状态代码的操作结果中。 操作结果帮助程序方法基于
ObjectResult
。
返回模型类型后,返回类型为 ObjectResult
。
以下操作方法使用 Ok
和 NotFound
帮助程序方法:
// GET: api/authors/search?namelike=th [HttpGet("Search")] public IActionResult Search(string namelike) { var result = _authors.GetByNameSubstring(namelike); if (!result.Any()) { return NotFound(namelike); } return Ok(result); }
默认情况下,ASP.NET Core 支持 application/json
、text/json
和 text/plain
媒体类型。 Fiddler 或 Postman 等工具可以设置 Accept
请求标头,来指定返回格式。 Accept
标头包含服务器支持的类型时,将返回该类型。 下一节将介绍如何添加其他格式化程序。
控制器操作可以返回 POCO(普通旧 CLR 对象)。 返回 POCO 时,运行时自动创建包装该对象的 ObjectResult
。 客户端将获得已格式化和序列化的对象。 若将返回的对象为 null
,将返回 204 No Content
响应。
返回对象类型:
// GET api/authors/RickAndMSFT [HttpGet("{alias}")] public Author Get(string alias) { return _authors.GetByAlias(alias); }
在前面的代码中,请求有效作者别名将返回具有作者数据的 200 OK
响应。 请求无效别名将返回 204 No Content
响应。
Accept 标头
内容协商在 Accept
标头出现在请求中时发生。 请求包含 Accept 标头时,ASP.NET Core 将执行以下操作:
- 按首选顺序枚举 Accept 标头中的媒体类型。
- 尝试找到可以生成某种指定格式的响应的格式化程序。
若未找到可以满足客户端请求的格式化程序,ASP.NET Core 将指定以下操作:
- 已设置
406 Not Acceptable
时,将返回 MvcOptions,或者 - 尝试找到第一个可以生成响应的格式化程序。
如果没有配置实现所请求格式的格式化程序,那么使用第一个可以设置对象格式的格式化程序。 若请求中没有 Accept
标头:
- 将使用第一个可以处理对象的格式化程序来将响应序列化。
- 不执行任何协商。 服务器将决定要返回的格式。
如果 Accept 标头包含 */*
,则将忽略该标头,除非 RespectBrowserAcceptHeader
在 MvcOptions 上设置为 true。
浏览器和内容协商
与典型的 API 客户端不同的是,Web 浏览器提供 Accept
标头。 Web 浏览器指定多种格式,包括通配符。 默认情况下,当框架检测到请求来自浏览器时,将执行以下操作:
- 忽略
Accept
标头。 - 若未另行配置,将使用 JSON 返回内容。
这样,在使用 API 时,浏览器中的体验将更加一致。
若要将应用配置为采用浏览器 Accept 标头,请将 RespectBrowserAcceptHeader 设置为 true
:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { options.RespectBrowserAcceptHeader = true; // false by default }); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; // false by default }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
配置格式化程序
需要支持其他格式的应用可以添加相应的 NuGet 包,并配置支持。 输入和输出的格式化程序不同。 模型绑定使用输入格式化程序。 格式响应使用输出格式化程序。 有关创建自定义格式化程序的信息,请参阅自定义格式化程序。
添加 XML 格式支持
调用 AddXmlSerializerFormatters 来配置使用 XmlSerializer 实现的 XML 格式化程序:
public void ConfigureServices(IServiceCollection services) { services.AddControllers() .AddXmlSerializerFormatters(); }
前面的代码将使用 XmlSerializer
将结果序列化。
使用前面的代码时,控制器方法会基于请求的 Accept
标头返回相应的格式。
配置基于 System.Text.Json 的格式化程序
可以使用 Microsoft.AspNetCore.Mvc.JsonOptions.SerializerOptions
配置基于 System.Text.Json
的格式化程序的功能。
services.AddControllers().AddJsonOptions(options => { // Use the default property (Pascal) casing. options.SerializerOptions.PropertyNamingPolicy = null; // Configure a custom converter. options.SerializerOptions.Converters.Add(new MyCustomJsonConverter()); });
可以使用 JsonResult
配置基于每个操作的输出序列化选项。 例如:
public IActionResult Get() { return Json(model, new JsonSerializerOptions { options.WriteIndented = true, }); }
添加基于 Newtonsoft.Json 的 JSON 格式支持
ASP.NET Core 3.0 之前的版本中,默认设置使用通过 Newtonsoft.Json
包实现的 JSON 格式化程序。 在 ASP.NET Core 3.0 或更高版本中,默认 JSON 格式化程序基于 System.Text.Json
。 通过安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 包并在 Startup.ConfigureServices
中配置可以支持基于 Newtonsoft.Json
的格式化程序和功能。
public void ConfigureServices(IServiceCollection services) { services.AddControllers() .AddNewtonsoftJson(); }
某些功能可能不适用于基于 System.Text.Json
的格式化程序,而需要引用基于 Newtonsoft.Json
的格式化程序。 若应用符合以下情况,请继续使用基于 Newtonsoft.Json
的格式化程序:
- 使用
Newtonsoft.Json
属性。 例如,[JsonProperty]
或[JsonIgnore]
。 - 自定义序列化设置。
- 依赖
Newtonsoft.Json
提供的功能。 - 配置
Microsoft.AspNetCore.Mvc.JsonResult.SerializerSettings
。 ASP.NET Core 3.0 之前的版本中,JsonResult.SerializerSettings
接受特定于Newtonsoft.Json
的JsonSerializerSettings
的实例。 - 生成 OpenAPI 文档。
可以使用 Microsoft.AspNetCore.Mvc.MvcNewtonsoftJsonOptions.SerializerSettings
配置基于 Newtonsoft.Json
的格式化程序的功能:
services.AddControllers().AddNewtonsoftJson(options => { // Use the default property (Pascal) casing options.SerializerSettings.ContractResolver = new DefaultContractResolver(); // Configure a custom converter options.SerializerOptions.Converters.Add(new MyCustomJsonConverter()); });
可以使用 JsonResult
配置基于每个操作的输出序列化选项。 例如:
public IActionResult Get() { return Json(model, new JsonSerializerSettings { options.Formatting = Formatting.Indented, }); }
添加 XML 格式支持
XML 格式需要 Microsoft.AspNetCore.Mvc.Formatters.Xml NuGet 包。
调用 AddXmlSerializerFormatters 来配置使用 XmlSerializer 实现的 XML 格式化程序:
public void ConfigureServices(IServiceCollection services) { services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddXmlSerializerFormatters(); }
前面的代码将使用 XmlSerializer
将结果序列化。
使用前面的代码时,控制器方法应基于请求的 Accept
标头返回相应的格式。
指定格式
应用 [Produces]
筛选器,以限制响应格式。 如同大多筛选器,[Produces]
可以在操作层面、控制器层面或全局范围内应用:
[ApiController] [Route("[controller]")] [Produces("application/json")] public class WeatherForecastController : ControllerBase {
上述 [Produces]
筛选器将执行以下操作:
- 强制控制器内的所有操作返回 JSON 格式的响应。
- 若已配置其他格式化程序,并且客户端指定了其他格式,将返回 JSON。
有关详细信息,请参阅筛选器。
特例格式化程序
一些特例是使用内置格式化程序实现的。 默认情况下,string
返回类型的格式将设为 text/plain(如果通过 Accept
标头请求则为 text/html)。 可以通过删除 StringOutputFormatter 删除此行为。 在 ConfigureServices
方法中删除格式化程序。 有模型对象返回类型的操作将在返回 null
时返回 204 No Content
。 可以通过删除 HttpNoContentOutputFormatter 删除此行为。 以下代码删除 StringOutputFormatter
和 HttpNoContentOutputFormatter
。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { // requires using Microsoft.AspNetCore.Mvc.Formatters; options.OutputFormatters.RemoveType<StringOutputFormatter>(); options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>(); }); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // requires using Microsoft.AspNetCore.Mvc.Formatters; options.OutputFormatters.RemoveType<StringOutputFormatter>(); options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>(); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
如果没有 StringOutputFormatter
,内置 JSON 格式化程序将设置 string
返回类型的格式。 如果删除了内置 JSON 格式化程序并提供了 XML 格式化程序,则 XML 格式化程序将设置 string
返回类型的格式。 否则,string
返回类型返回 406 Not Acceptable
。
没有 HttpNoContentOutputFormatter
,null 对象将使用配置的格式化程序来进行格式设置。 例如:
- JSON 格式化程序返回正文为
null
的响应。 - 设置属性
xsi:nil="true"
时,XML 格式化程序返回空 XML 元素。
响应格式 URL 映射
客户端可以在 URL 中请求特定格式,例如:
- 在查询字符串中,或在路径中。
- 使用格式特定的文件扩展名,如 .xml 或 .json。
请求路径的映射必须在 API 使用的路由中指定。 例如:
[Route("api/[controller]")] [ApiController] [FormatFilter] public class ProductsController : ControllerBase { [HttpGet("{id}.{format?}")] public Product Get(int id) {
上述路由将允许指定所请求格式为可选文件扩展名。 [FormatFilter]
属性检查 RouteData
中格式值是否存在,并在响应创建时将响应格式映射到相应格式化程序。
路由 | 格式化程序 |
---|---|
/api/products/5 |
默认输出格式化程序 |
/api/products/5.json |
JSON 格式化程序(如配置) |
/api/products/5.xml |
XML 格式化程序(如配置) |