设置 ASP.NET Core Web API 中响应数据的格式

ASP.NET Core MVC 支持对使用指定格式或对客户端请求响应的响应数据进行格式设置。

特定于格式的操作结果

一些操作结果类型特定于特殊格式,例如 JsonResultContentResult。 这些操作可以返回始终使用指定格式的结果,这将忽略客户端对不同格式的请求。 例如,返回 JsonResult 将返回 JSON 格式的数据,返回 ContentResult 将返回纯文本格式的字符串数据。

无需操作返回任意特定类型。 ASP.NET Core 支持任何对象返回值。 对于返回非 IActionResult 类型对象的操作的结果,将使用相应的 IOutputFormatter 实现来对这些结果进行序列化。 有关详细信息,请参阅 ASP.NET Core Web API 中的控制器操作返回类型

默认情况下,内置的帮助程序方法 ControllerBase.Ok 返回 JSON 格式的数据:

[HttpGet]
public IActionResult Get() =>
    Ok(_todoItemStore.GetList());

示例代码将返回 todo 项的列表。 在 F12 浏览器开发人员工具或 http-repl 中使用上述代码将会显示:

  • 包含 content-type: application/json; charset=utf-8 的响应头
  • 请求标头。 例如 Accept 标头。 上述代码将忽略 Accept 标头。

若要返回纯文本格式数据,请使用 ContentResultContent 帮助程序:

[HttpGet("Version")]
public ContentResult GetVersion() =>
    Content("v1.0.0");

在上述代码中,返回的 text/plainContent-Type

对于包含多个返回类型的操作,将返回 IActionResult。 例如,基于操作的结果返回不同的 HTTP 状态代码时。

内容协商

当客户端指定 Accept 标头时,会发生内容协商。 ASP.NET Core 使用的默认格式是 JSON。 内容协商有以下特点:

  • ObjectResult 实现。
  • 内置于从帮助程序方法返回的特定于状态代码的操作结果中。 操作结果帮助程序方法基于 ObjectResult

返回一个模型类型时,返回类型为 ObjectResult

以下操作方法使用 OkNotFound 帮助程序方法:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

默认情况下,ASP.NET Core 支持以下媒体类型:

  • application/json
  • text/json
  • text/plain

Fiddler 或 curl 等工具可以设置 Accept 请求标头来指定返回格式。 Accept 标头包含服务器支持的类型时,将返回该类型。 下一节将介绍如何添加其他格式化程序。

控制器操作可以返回 POCO(普通旧 CLR 对象)。 返回 POCO 时,运行时自动创建包装该对象的 ObjectResult。 客户端将获得已格式化和序列化的对象。 若将返回的对象为 null,将返回 204 No Content 响应。

以下示例返回一个对象类型:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id) =>
    _todoItemStore.GetById(id);

在上述代码中,对有效 todo 项的请求将返回 200 OK 响应。 对无效 todo 项的请求将返回 204 No Content 响应。

Accept 标头

内容协商在 Accept 标头出现在请求中时发生。 请求包含 Accept 标头时,ASP.NET Core 将执行以下操作:

  • 按首选顺序枚举 Accept 标头中的媒体类型。
  • 尝试找到可以生成某种指定格式的响应的格式化程序。

若未找到可以满足客户端请求的格式化程序,ASP.NET Core 将指定以下操作:

如果没有配置实现所请求格式的格式化程序,那么使用第一个可以设置对象格式的格式化程序。 若请求中没有 Accept 标头:

  • 将使用第一个可以处理对象的格式化程序来将响应序列化。
  • 不执行任何协商。 服务器将决定要返回的格式。

如果 Accept 标头包含 */*,则将忽略该标头,除非 RespectBrowserAcceptHeaderMvcOptions 上设置为 true。

浏览器和内容协商

与典型的 API 客户端不同的是,Web 浏览器提供 Accept 标头。 Web 浏览器指定多种格式,包括通配符。 默认情况下,当框架检测到请求来自浏览器时,将执行以下操作:

  • 忽略 Accept 标头。
  • 若未另行配置,将使用 JSON 返回内容。

这样,在使用 API 时,各种浏览器中的体验将更加一致。

若要将应用配置为接受浏览器 Accept 标头,请将 RespectBrowserAcceptHeader 属性设置为 true

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

配置格式化程序

需要支持额外格式的应用可以添加相应的 NuGet 包并配置支持。 输入和输出的格式化程序不同。 模型绑定使用输入格式化程序。 格式响应使用输出格式化程序。 有关创建自定义格式化程序的信息,请参阅自定义格式化程序

添加 XML 格式支持

若要配置使用 XmlSerializer 实现的 XML 格式化程序,请调用 AddXmlSerializerFormatters

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

使用前面的代码时,控制器方法会基于请求的 Accept 标头返回相应的格式。

配置基于 System.Text.Json 的格式化程序

若要配置基于 System.Text.Json 的格式化程序的功能,请使用 Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions。 以下突出显示的代码配置 PascalCase 格式,而不是默认的 camelCase 格式:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

以下操作方法调用 ControllerBase.Problem 来创建 ProblemDetails 响应:

[HttpGet("Error")]
public IActionResult GetError() =>
    Problem("Something went wrong.");

ProblemDetails 响应始终为 camelCase 格式,即使应用将格式设置为 PascalCase 也是如此。 ProblemDetails 遵循 RFC 7807,这将指定为小写。

若要为特定操作配置输出序列化选项,请使用 JsonResult。 例如:

[HttpGet]
public IActionResult Get() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions
        {
            PropertyNamingPolicy = null
        });

添加基于 Newtonsoft.Json 的 JSON 格式支持

默认的 JSON 格式化程序使用 System.Text.Json。 若要使用基于 Newtonsoft.Json 的格式化程序,请安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 包并在 Program.cs 中进行配置:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

在上述代码中,对 AddNewtonsoftJson 的调用会将以下 Web API、MVC 和 Razor Pages 功能配置为使用 Newtonsoft.Json

某些功能可能不适用于基于 System.Text.Json 的格式化程序,而需要引用基于 Newtonsoft.Json 的格式化程序。 当应用符合以下情况时,请继续使用基于 Newtonsoft.Json 的格式化程序:

  • 使用 Newtonsoft.Json 属性。 例如,[JsonProperty][JsonIgnore]
  • 自定义序列化设置。
  • 依赖 Newtonsoft.Json 提供的功能。

若要配置基于 Newtonsoft.Json 的格式化程序的功能,请使用 SerializerSettings

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

若要为特定操作配置输出序列化选项,请使用 JsonResult。 例如:

[HttpGet]
public IActionResult GetNewtonsoftJson() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver()
        });

指定格式

应用 [Produces] 筛选器,以限制响应格式。 如同大多筛选器[Produces] 可以在操作层面、控制器层面或全局范围内应用:

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

上述 [Produces] 筛选器将执行以下操作:

  • 强制控制器中的所有操作返回 POCO(普通旧 CLR 对象)或 ObjectResult 及其派生类型的 JSON 格式响应。
  • 返回 JSON 格式的响应,即使配置了其他格式化程序并且客户端指定了其他格式也是如此。

有关详细信息,请参阅筛选器

特例格式化程序

一些特例是使用内置格式化程序实现的。 默认情况下,string 返回类型的格式将设为 text/plain(如果通过 Accept 标头请求则为 text/html)。 可以通过删除 StringOutputFormatter 删除此行为。 格式化程序会从 Program.cs 中删除。 有模型对象返回类型的操作将在返回 null 时返回 204 No Content。 可以通过删除 HttpNoContentOutputFormatter 删除此行为。 以下代码删除 StringOutputFormatterHttpNoContentOutputFormatter

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

如果没有 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 使用的路由中指定。 例如:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore) =>
        _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id) =>
        _todoItemStore.GetById(id);

上述路由将允许使用可选文件扩展名来指定请求的格式。 [FormatFilter] 属性检查 RouteData 中格式值是否存在,并在响应创建时将响应格式映射到相应格式化程序。

路由 格式化程序
/api/todoitems/5 默认输出格式化程序
/api/todoitems/5.json JSON 格式化程序(如配置)
/api/todoitems/5.xml XML 格式化程序(如配置)

多态反序列化

内置功能提供有限范围的多态序列化,但完全不支持反序列化。 反序列化需要自定义转换器。 有关多态反序列化的完整示例,请参阅多态反序列化

其他资源

ASP.NET Core MVC 支持设置响应数据的格式。 可以使用特定格式或响应客户端请求的格式,来设置响应数据的格式。

查看或下载示例代码如何下载

特定于格式的操作结果

一些操作结果类型特定于特殊格式,例如 JsonResultContentResult。 操作可以返回使用特定格式设置格式的结果,而不考虑客户端首选项。 例如,返回 JsonResult,将返回 JSON 格式的数据。 返回 ContentResult 或字符串,将返回纯文本格式的字符串数据。

无需操作返回任意特定类型。 ASP.NET Core 支持任何对象返回值。 对于返回非 IActionResult 类型对象的操作的结果,将使用相应的 IOutputFormatter 实现来对这些结果进行序列化。 有关详细信息,请参阅 ASP.NET Core Web API 中的控制器操作返回类型

内置的帮助程序方法 Ok 返回 JSON 格式的数据:

// GET: api/authors
[HttpGet]
public ActionResult Get()
{
    return Ok(_authors.List());
}

示例下载返回作者列表。 在 F12 浏览器开发人员工具或 http-repl 中使用上述代码:

  • 将显示包含 content-type: application/json; charset=utf-8 的响应头
  • 将显示请求标头。 例如 Accept 标头。 上述代码将忽略 Accept 标头。

若要返回纯文本格式数据,请使用 ContentResultContent 帮助程序:

// GET api/authors/about
[HttpGet("About")]
public ContentResult About()
{
    return Content("An API listing authors of docs.asp.net.");
}

在上述代码中,返回的 text/plainContent-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

以下操作方法使用 OkNotFound 帮助程序方法:

// 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/jsontext/jsontext/plain 媒体类型。 Fiddlerhttp-repl 等工具可以设置 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 将指定以下操作:

如果没有配置实现所请求格式的格式化程序,那么使用第一个可以设置对象格式的格式化程序。 若请求中没有 Accept 标头:

  • 将使用第一个可以处理对象的格式化程序来将响应序列化。
  • 不执行任何协商。 服务器将决定要返回的格式。

如果 Accept 标头包含 */*,则将忽略该标头,除非 RespectBrowserAcceptHeaderMvcOptions 上设置为 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
    });
}

配置格式化程序

需要支持其他格式的应用可以添加相应的 NuGet 包,并配置支持。 输入和输出的格式化程序不同。 模型绑定使用输入格式化程序。 格式响应使用输出格式化程序。 有关创建自定义格式化程序的信息,请参阅自定义格式化程序

添加 XML 格式支持

调用 AddXmlSerializerFormatters 来配置使用 XmlSerializer 实现的 XML 格式化程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddXmlSerializerFormatters();
}

前面的代码将使用 XmlSerializer 将结果序列化。

使用前面的代码时,控制器方法会基于请求的 Accept 标头返回相应的格式。

配置基于 System.Text.Json 的格式化程序

可以使用 Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions 配置基于 System.Text.Json 的格式化程序的功能。 默认格式为 camelCase。 以下突出显示的代码设置 PascalCase 格式:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddJsonOptions(options =>
            options.JsonSerializerOptions.PropertyNamingPolicy = null);
}

以下操作方法调用 ControllerBase.Problem 来创建 ProblemDetails 响应:

[HttpGet("error")]
public IActionResult GetError()
{
    return Problem("Something went wrong!");
}

通过使用上述代码:

  • https://localhost:5001/WeatherForecast/temperature 返回 PascalCase。
  • https://localhost:5001/WeatherForecast/error 返回 camelCase。 错误响应始终为 camelCase 格式,即使应用将格式设置为 PascalCase 也是如此。 ProblemDetails 遵循 RFC 7807,这将指定为小写

以下代码设置 PascalCase 并添加自定义转换器:

services.AddControllers().AddJsonOptions(options =>
{
    // Use the default property (Pascal) casing.
    options.JsonSerializerOptions.PropertyNamingPolicy = null;

    // Configure a custom converter.
    options.JsonSerializerOptions.Converters.Add(new MyCustomJsonConverter());
});

可以使用 JsonResult 配置基于每个操作的输出序列化选项。 例如:

public IActionResult Get()
{
    return Json(model, new JsonSerializerOptions
    {
        WriteIndented = true,
    });
}

添加基于 Newtonsoft.Json 的 JSON 格式支持

默认的 JSON 格式化程序基于 System.Text.Json。 通过安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 包并在 Startup.ConfigureServices 中进行配置可以实现对基于 Newtonsoft.Json 的格式化程序和功能的支持。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}

在上述代码中,对 AddNewtonsoftJson 的调用会将以下 Web API、MVC 和 Razor Pages 功能配置为使用 Newtonsoft.Json

某些功能可能不适用于基于 System.Text.Json 的格式化程序,而需要引用基于 Newtonsoft.Json 的格式化程序。 当应用符合以下情况时,请继续使用基于 Newtonsoft.Json 的格式化程序:

  • 使用 Newtonsoft.Json 属性。 例如,[JsonProperty][JsonIgnore]
  • 自定义序列化设置。
  • 依赖 Newtonsoft.Json 提供的功能。

可以使用 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.SerializerSettings.Converters.Add(new MyCustomJsonConverter());
});

可以使用 JsonResult 配置基于每个操作的输出序列化选项。 例如:

public IActionResult Get()
{
    return Json(model, new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
    });
}

指定格式

应用 [Produces] 筛选器,以限制响应格式。 如同大多筛选器[Produces] 可以在操作层面、控制器层面或全局范围内应用:

[ApiController]
[Route("[controller]")]
[Produces("application/json")]
public class WeatherForecastController : ControllerBase
{

上述 [Produces] 筛选器将执行以下操作:

  • 强制控制器中的所有操作返回 POCO(普通旧 CLR 对象)或 ObjectResult 及其派生类型的 JSON 格式响应。
  • 若已配置其他格式化程序,并且客户端指定了其他格式,将返回 JSON。

有关详细信息,请参阅筛选器

特例格式化程序

一些特例是使用内置格式化程序实现的。 默认情况下,string 返回类型的格式将设为 text/plain(如果通过 Accept 标头请求则为 text/html)。 可以通过删除 StringOutputFormatter 删除此行为。 在 ConfigureServices 方法中删除格式化程序。 有模型对象返回类型的操作将在返回 null 时返回 204 No Content。 可以通过删除 HttpNoContentOutputFormatter 删除此行为。 以下代码删除 StringOutputFormatterHttpNoContentOutputFormatter

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        // requires using Microsoft.AspNetCore.Mvc.Formatters;
        options.OutputFormatters.RemoveType<StringOutputFormatter>();
        options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
    });
}

如果没有 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 格式化程序(如配置)

ASP.NET Core MVC 支持对使用指定格式或对客户端请求响应的响应数据进行格式设置。

特定于格式的操作结果

一些操作结果类型特定于特殊格式,例如 JsonResultContentResult。 这些操作可以返回始终使用指定格式的结果,这将忽略客户端对不同格式的请求。 例如,返回 JsonResult 将返回 JSON 格式的数据,返回 ContentResult 将返回纯文本格式的字符串数据。

无需操作返回任意特定类型。 ASP.NET Core 支持任何对象返回值。 对于返回非 IActionResult 类型对象的操作的结果,将使用相应的 IOutputFormatter 实现来对这些结果进行序列化。 有关详细信息,请参阅 ASP.NET Core Web API 中的控制器操作返回类型

默认情况下,内置的帮助程序方法 ControllerBase.Ok 返回 JSON 格式的数据:

[HttpGet]
public IActionResult Get()
    => Ok(_todoItemStore.GetList());

示例代码将返回 todo 项的列表。 在 F12 浏览器开发人员工具或 http-repl 中使用上述代码将会显示:

  • 包含 content-type: application/json; charset=utf-8 的响应头
  • 请求标头。 例如 Accept 标头。 上述代码将忽略 Accept 标头。

若要返回纯文本格式数据,请使用 ContentResultContent 帮助程序:

[HttpGet("Version")]
public ContentResult GetVersion()
    => Content("v1.0.0");

在上述代码中,返回的 text/plainContent-Type

对于包含多个返回类型的操作,将返回 IActionResult。 例如,基于操作的结果返回不同的 HTTP 状态代码时。

内容协商

当客户端指定 Accept 标头时,会发生内容协商。 ASP.NET Core 使用的默认格式是 JSON。 内容协商有以下特点:

  • ObjectResult 实现。
  • 内置于从帮助程序方法返回的特定于状态代码的操作结果中。 操作结果帮助程序方法基于 ObjectResult

返回一个模型类型时,返回类型为 ObjectResult

以下操作方法使用 OkNotFound 帮助程序方法:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

默认情况下,ASP.NET Core 支持以下媒体类型:

  • application/json
  • text/json
  • text/plain

Fiddlerhttp-repl 等工具可以设置 Accept 请求头,来指定返回格式。 Accept 标头包含服务器支持的类型时,将返回该类型。 下一节将介绍如何添加其他格式化程序。

控制器操作可以返回 POCO(普通旧 CLR 对象)。 返回 POCO 时,运行时自动创建包装该对象的 ObjectResult。 客户端将获得已格式化和序列化的对象。 若将返回的对象为 null,将返回 204 No Content 响应。

以下示例返回一个对象类型:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id)
    => _todoItemStore.GetById(id);

在上述代码中,对有效 todo 项的请求将返回 200 OK 响应。 对无效 todo 项的请求将返回 204 No Content 响应。

Accept 标头

内容协商在 Accept 标头出现在请求中时发生。 请求包含 Accept 标头时,ASP.NET Core 将执行以下操作:

  • 按首选顺序枚举 Accept 标头中的媒体类型。
  • 尝试找到可以生成某种指定格式的响应的格式化程序。

若未找到可以满足客户端请求的格式化程序,ASP.NET Core 将指定以下操作:

如果没有配置实现所请求格式的格式化程序,那么使用第一个可以设置对象格式的格式化程序。 若请求中没有 Accept 标头:

  • 将使用第一个可以处理对象的格式化程序来将响应序列化。
  • 不执行任何协商。 服务器将决定要返回的格式。

如果 Accept 标头包含 */*,则将忽略该标头,除非 RespectBrowserAcceptHeaderMvcOptions 上设置为 true。

浏览器和内容协商

与典型的 API 客户端不同的是,Web 浏览器提供 Accept 标头。 Web 浏览器指定多种格式,包括通配符。 默认情况下,当框架检测到请求来自浏览器时,将执行以下操作:

  • 忽略 Accept 标头。
  • 若未另行配置,将使用 JSON 返回内容。

这样,在使用 API 时,各种浏览器中的体验将更加一致。

若要将应用配置为接受浏览器 Accept 标头,请将 RespectBrowserAcceptHeader 属性设置为 true

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

配置格式化程序

需要支持额外格式的应用可以添加相应的 NuGet 包并配置支持。 输入和输出的格式化程序不同。 模型绑定使用输入格式化程序。 格式响应使用输出格式化程序。 有关创建自定义格式化程序的信息,请参阅自定义格式化程序

添加 XML 格式支持

若要配置使用 XmlSerializer 实现的 XML 格式化程序,请调用 AddXmlSerializerFormatters

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

使用前面的代码时,控制器方法会基于请求的 Accept 标头返回相应的格式。

配置基于 System.Text.Json 的格式化程序

若要配置基于 System.Text.Json 的格式化程序的功能,请使用 Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions。 以下突出显示的代码配置 PascalCase 格式,而不是默认的 camelCase 格式:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

若要为特定操作配置输出序列化选项,请使用 JsonResult。 例如:

[HttpGet]
public IActionResult Get() 
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions { PropertyNamingPolicy = null });

添加基于 Newtonsoft.Json 的 JSON 格式支持

默认的 JSON 格式化程序使用 System.Text.Json。 若要使用基于 Newtonsoft.Json 的格式化程序,请安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 包并在 Program.cs 中进行配置:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

在上述代码中,对 AddNewtonsoftJson 的调用会将以下 Web API、MVC 和 Razor Pages 功能配置为使用 Newtonsoft.Json

某些功能可能不适用于基于 System.Text.Json 的格式化程序,而需要引用基于 Newtonsoft.Json 的格式化程序。 当应用符合以下情况时,请继续使用基于 Newtonsoft.Json 的格式化程序:

  • 使用 Newtonsoft.Json 属性。 例如,[JsonProperty][JsonIgnore]
  • 自定义序列化设置。
  • 依赖 Newtonsoft.Json 提供的功能。

若要配置基于 Newtonsoft.Json 的格式化程序的功能,请使用 SerializerSettings

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

若要为特定操作配置输出序列化选项,请使用 JsonResult。 例如:

[HttpGet]
public IActionResult GetNewtonsoftJson()
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() });

设置 ProblemDetailsValidationProblemDetails 响应的格式

以下操作方法调用 ControllerBase.Problem 来创建 ProblemDetails 响应:

[HttpGet("Error")]
public IActionResult GetError()
    => Problem("Something went wrong.");

ProblemDetails 响应始终为 camelCase 格式,即使应用将格式设置为 PascalCase 也是如此。 ProblemDetails 遵循 RFC 7807,这将指定为小写。

[ApiController] 特性应用于控制器类时,控制器会在模型验证失败时创建 ValidationProblemDetails 响应。 此响应包括一个字典,该字典使用模型的属性名称作为错误键(未更改)。 例如,以下模型包含需要验证的单个属性:

public class SampleModel
{
    [Range(1, 10)]
    public int Value { get; set; }
}

默认情况下,当 Value 属性无效时,返回的 ValidationProblemDetails 响应使用错误键 Value,如以下示例所示:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "Value": [
      "The field Value must be between 1 and 10."
    ]
  }
}

若要设置用作错误键的属性名称的格式,请将 IMetadataDetailsProvider 的实现添加到 MvcOptions.ModelMetadataDetailsProviders 集合中。 以下示例添加一个基于 System.Text.Json 的实现 SystemTextJsonValidationMetadataProvider,该实现默认将属性名称格式化为 camelCase:

builder.Services.AddControllers();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new SystemTextJsonValidationMetadataProvider());
});

SystemTextJsonValidationMetadataProvider 还在其构造函数中接受 JsonNamingPolicy 的实现,该实现指定用于设置属性名称格式的自定义命名策略。

若要在模型中设置属性的自定义名称,请在属性上使用 [JsonPropertyName] 特性:

public class SampleModel
{
    [Range(1, 10)]
    [JsonPropertyName("sampleValue")]
    public int Value { get; set; }
}

Value 属性无效时,上述模型返回的 ValidationProblemDetails 响应使用错误键 sampleValue,如以下示例所示:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "sampleValue": [
      "The field Value must be between 1 and 10."
    ]
  }
}

若要使用 Newtonsoft.Json 设置 ValidationProblemDetails 响应的格式,请使用 NewtonsoftJsonValidationMetadataProvider

builder.Services.AddControllers()
    .AddNewtonsoftJson();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new NewtonsoftJsonValidationMetadataProvider());
});

默认情况下,NewtonsoftJsonValidationMetadataProvider 将属性名称的格式设置为 camelCase。 NewtonsoftJsonValidationMetadataProvider 还在其构造函数中接受 NamingPolicy 的实现,该实现指定用于设置属性名称格式的自定义命名策略。 若要为模型中的属性设置自定义名称,请使用 [JsonProperty] 特性。

指定格式

应用 [Produces] 筛选器,以限制响应格式。 如同大多筛选器[Produces] 可以在操作层面、控制器层面或全局范围内应用:

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

上述 [Produces] 筛选器将执行以下操作:

  • 强制控制器中的所有操作返回 POCO(普通旧 CLR 对象)或 ObjectResult 及其派生类型的 JSON 格式响应。
  • 返回 JSON 格式的响应,即使配置了其他格式化程序并且客户端指定了其他格式也是如此。

有关详细信息,请参阅筛选器

特例格式化程序

一些特例是使用内置格式化程序实现的。 默认情况下,string 返回类型的格式将设为 text/plain(如果通过 Accept 标头请求则为 text/html)。 可以通过删除 StringOutputFormatter 删除此行为。 格式化程序会从 Program.cs 中删除。 有模型对象返回类型的操作将在返回 null 时返回 204 No Content。 可以通过删除 HttpNoContentOutputFormatter 删除此行为。 以下代码删除 StringOutputFormatterHttpNoContentOutputFormatter

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

如果没有 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 使用的路由中指定。 例如:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore)
        => _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id)
        => _todoItemStore.GetById(id);

上述路由将允许使用可选文件扩展名来指定请求的格式。 [FormatFilter] 属性检查 RouteData 中格式值是否存在,并在响应创建时将响应格式映射到相应格式化程序。

路由 格式化程序
/api/todoitems/5 默认输出格式化程序
/api/todoitems/5.json JSON 格式化程序(如配置)
/api/todoitems/5.xml XML 格式化程序(如配置)

多态反序列化

内置功能提供有限范围的多态序列化,但完全不支持反序列化。 反序列化需要自定义转换器。 有关多态反序列化的完整示例,请参阅多态反序列化

其他资源