在 ASP.NET Core Web API 中格式化回應資料

ASP.NET Core MVC 支援使用指定格式或回應用戶端要求的回應資料格式化。

格式特定動作結果

某些動作結果類型是特定格式所特有的,例如 JsonResultContentResult。 動作可以傳回一律使用指定格式的結果,忽略用戶端的不同格式要求。 例如,傳回 JsonResult 會傳回 JSON 格式的資料,且傳回 ContentResult 會傳回純文字格式的字串資料。

不需要動作即可傳回任何特定型別。 ASP.NET Core 支援任何物件傳回值。 使用適當的 IOutputFormatter 實作來序列化回傳物件不是 IActionResult 型別的動作結果。 如需詳細資訊,請參閱 ASP.NET Core Web API 中的控制器動作傳回型別

根據預設,內建協助程式方法 ControllerBase.Ok 會傳回 JSON 格式資料:

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

範例程式碼會傳回 ToDo 項目清單。 使用 F12 瀏覽器開發人員工具或 HTTP-repl 搭配先前的程式代碼會顯示:

  • 含有內容型別:application/json; charset=utf-8 的回應標頭。
  • 要求標頭。 例如,Accept 標頭。 上述程式碼會忽略 Accept 標頭。

若要傳回純文字格式化資料,請使用 ContentResultContent 協助程式:

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

在上述程式碼中,傳回的 Content-Typetext/plain

若動作使用多種傳回型別,則會傳回 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

FiddlerPostman 之類的工具可以設定 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 標頭包含 */*,則除非 MvcOptions 上的 RespectBrowserAcceptHeader 設定為 true,否則會忽略標頭。

瀏覽器和內容交涉

與一般 API 用戶端不同,網頁瀏覽器會提供 Accept 標頭。 網頁瀏覽器會指定許多格式,包括萬用字元。 根據預設,當架構偵測到要求是來自於瀏覽器時:

  • 會忽略 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 物件) 的 JSON 格式化回應或 ObjectResult 及其衍生型別。
  • 即使已設定其他格式器,且用戶端指定了不同格式,仍會傳回 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 本文的回應。
  • XML 格式器會傳回已設定 xsi:nil="true" 屬性的空白 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 支援任何物件傳回值。 使用適當的 IOutputFormatter 實作來序列化回傳物件不是 IActionResult 型別的動作結果。 如需詳細資訊,請參閱 ASP.NET Core Web API 中的控制器動作傳回型別

內建的協助程式方法 Ok 會傳回 JSON 格式資料:

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

範例下載會傳回作者清單。 使用 F12 瀏覽器開發人員工具或 HTTP-repl 搭配先前的程式代碼:

  • 顯示含有內容型別: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.");
}

在上述程式碼中,傳回的 Content-Typetext/plain。 傳回字串會傳遞 text/plainContent-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 標頭包含 */*,則除非 MvcOptions 上的 RespectBrowserAcceptHeader 設定為 true,否則會忽略標頭。

瀏覽器和內容交涉

與一般 API 用戶端不同,網頁瀏覽器會提供 Accept 標頭。 網頁瀏覽器會指定許多格式,包括萬用字元。 根據預設,當架構偵測到要求是來自於瀏覽器時:

  • 會忽略 Accept 標頭。
  • 除非另有設定,否則內容會以 JSON 傳回。

此方法會在取用 API 時,提供更一致的瀏覽器體驗。

若要將應用程式設定為使用瀏覽器 Accept 標頭,請將 RespectBrowserAcceptHeader 設定為 true

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.RespectBrowserAcceptHeader = true; // false by default
    });
}

設定格式器

需要支援其他格式的應用程式可以新增適當的 NuGet 套件並設定支援。 輸入和輸出有個別的格式器。 輸入格式器由模型繫結使用。 輸出格式器可用來格式化回應。 如需建立自訂格式器的相關資訊,請參閱自訂格式器

新增 XML 格式支援

若要設定使用 XmlSerializer 實作的 XML 格式器,請呼叫 AddXmlSerializerFormatters

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 為基礎。 在 Startup.ConfigureServices 中安裝及設定 Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet 套件後,即可使用 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 物件) 的 JSON 格式化回應或 ObjectResult 及其衍生型別。
  • 如果已設定其他格式器,且用戶端指定了不同格式,則會傳回 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 本文的回應。
  • XML 格式器會傳回已設定 xsi:nil="true" 屬性的空白 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 支援任何物件傳回值。 使用適當的 IOutputFormatter 實作來序列化回傳物件不是 IActionResult 型別的動作結果。 如需詳細資訊,請參閱 ASP.NET Core Web API 中的控制器動作傳回型別

根據預設,內建協助程式方法 ControllerBase.Ok 會傳回 JSON 格式資料:

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

範例程式碼會傳回 ToDo 項目清單。 使用 F12 瀏覽器開發人員工具或 HTTP-repl 搭配先前的程式代碼會顯示:

  • 含有內容型別:application/json; charset=utf-8 的回應標頭。
  • 要求標頭。 例如,Accept 標頭。 上述程式碼會忽略 Accept 標頭。

若要傳回純文字格式化資料,請使用 ContentResultContent 協助程式:

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

在上述程式碼中,傳回的 Content-Typetext/plain

若動作使用多種傳回型別,則會傳回 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 標頭包含 */*,則除非 MvcOptions 上的 RespectBrowserAcceptHeader 設定為 true,否則會忽略標頭。

瀏覽器和內容交涉

與一般 API 用戶端不同,網頁瀏覽器會提供 Accept 標頭。 網頁瀏覽器會指定許多格式,包括萬用字元。 根據預設,當架構偵測到要求是來自於瀏覽器時:

  • 會忽略 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; }
}

根據預設,傳回的 ValidationProblemDetails 回應會在 Value 屬性無效時使用 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; }
}

針對上述模型傳回的 ValidationProblemDetails 回應會在 Value 屬性無效時使用 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 物件) 的 JSON 格式化回應或 ObjectResult 及其衍生型別。
  • 即使已設定其他格式器,且用戶端指定了不同格式,仍會傳回 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 本文的回應。
  • XML 格式器會傳回已設定 xsi:nil="true" 屬性的空白 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 格式器 (如果已設定)

多型還原序列化

內建功能提供有限的多形序列化範圍,但完全不支援還原序列化。 還原序列化需要自訂轉換器。 如需多型還原序列化的完整範例,請參閱多型還原序列化

其他資源