使用 ASP.NET Core 建置 Web APIBuild web APIs with ASP.NET Core

作者:Scott AddieBy Scott Addie

檢視或下載範例程式碼 (英文) (如何下載)View or download sample code (how to download)

本文件說明如何在 ASP.NET Core 中建置 Web API,以及每項功能的最佳使用時機。This document explains how to build a web API in ASP.NET Core and when it's most appropriate to use each feature.

來自 ControllerBase 的衍生類別Derive class from ControllerBase

繼承自用作為 Web API 的控制器中之 ControllerBase 類別。Inherit from the ControllerBase class in a controller that's intended to serve as a web API. 例如:For example:

[Produces("application/json")]
[Route("api/[controller]")]
public class PetsController : ControllerBase
{
    private readonly PetsRepository _repository;

    public PetsController(PetsRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public async Task<ActionResult<List<Pet>>> GetAllAsync()
    {
        return await _repository.GetPetsAsync();
    }

    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<Pet>> GetByIdAsync(int id)
    {
        var pet = await _repository.GetPetAsync(id);

        if (pet == null)
        {
            return NotFound();
        }

        return pet;
    }

    [HttpPost]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<Pet>> CreateAsync(Pet pet)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        await _repository.AddPetAsync(pet);

        return CreatedAtAction(nameof(GetByIdAsync),
            new { id = pet.Id }, pet);
    }
}
[Produces("application/json")]
[Route("api/[controller]")]
public class PetsController : ControllerBase
{
    private readonly PetsRepository _repository;

    public PetsController(PetsRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    [ProducesResponseType(typeof(IEnumerable<Pet>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetAllAsync()
    {
        var pets = await _repository.GetPetsAsync();

        return Ok(pets);
    }

    [HttpGet("{id}")]
    [ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetByIdAsync(int id)
    {
        var pet = await _repository.GetPetAsync(id);

        if (pet == null)
        {
            return NotFound();
        }

        return Ok(pet);
    }

    [HttpPost]
    [ProducesResponseType(typeof(Pet), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> CreateAsync([FromBody] Pet pet)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        await _repository.AddPetAsync(pet);

        return CreatedAtAction(nameof(GetByIdAsync),
            new { id = pet.Id }, pet);
    }
}

ControllerBase 類別可用來存取數個屬性和方法。The ControllerBase class provides access to several properties and methods. 在上述程式碼中,範例包含 BadRequest(ModelStateDictionary)CreatedAtAction(String, Object, Object)In the preceding code, examples include BadRequest(ModelStateDictionary) and CreatedAtAction(String, Object, Object). 您可以在動作方法內呼叫這些方法,以分別傳回 HTTP 400 和 201 狀態碼。These methods are called within action methods to return HTTP 400 and 201 status codes, respectively. 可以存取 ModelState 屬性 (亦由 ControllerBase 提供),以處理要求模型驗證。The ModelState property, also provided by ControllerBase, is accessed to handle request model validation.

使用 ApiController 屬性的註釋Annotation with ApiController attribute

ASP.NET Core 2.1 新增了 [ApiController] 屬性代表 Web API 控制器類別。ASP.NET Core 2.1 introduces the [ApiController] attribute to denote a web API controller class. 例如:For example:

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase

透過 SetCompatibilityVersion 所設定的 2.1 或更新相容性版本必須在控制器層級使用此屬性。A compatibility version of 2.1 or later, set via SetCompatibilityVersion, is required to use this attribute at the controller level. 舉例來說,Startup.ConfigureServices 中的醒目提示程式碼會設定 2.1 相容性旗標:For example, the highlighted code in Startup.ConfigureServices sets the 2.1 compatibility flag:

services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

如需詳細資訊,請參閱ASP.NET Core MVC 的相容性版本For more information, see ASP.NET Core MVC 的相容性版本.

在 ASP.NET Core 2.2 或更新版本中,[ApiController] 屬性可以套用至組件。In ASP.NET Core 2.2 or later, the [ApiController] attribute can be applied to an assembly. 以這種方式標註會將 Web API 行為套用至組件中的所有控制器。Annotation in this manner applies web API behavior to all controllers in the assembly. 請注意,沒有任何方法可以退出個別控制器。Beware that there's no way to opt out for individual controllers. 建議您,組件層級屬性應套用至 Startup 類別:As a recommendation, assembly-level attributes should be applied to the Startup class:

[assembly: ApiController]
namespace WebApiSample.Api._22
{
    public class Startup
    {

透過 SetCompatibilityVersion 所設定的 2.2 或更新相容性版本必須在組件層級使用此屬性。A compatibility version of 2.2 or later, set via SetCompatibilityVersion, is required to use this attribute at the assembly level.

[ApiController] 屬性通常會與 ControllerBase 搭配使用,為控制站啟用 REST 特定行為。The [ApiController] attribute is commonly coupled with ControllerBase to enable REST-specific behavior for controllers. ControllerBase 可讓您存取 NotFoundFile 等方法。ControllerBase provides access to methods such as NotFound and File.

另一個方法是建立標註了 [ApiController] 屬性的自訂基底控制器類別:Another approach is to create a custom base controller class annotated with the [ApiController] attribute:

[ApiController]
public abstract class MyApiControllerBase : ControllerBase
{
}

下列章節說明該屬性新增的便利功能。The following sections describe convenience features added by the attribute.

HTTP 400 自動回應Automatic HTTP 400 responses

模型驗證錯誤會自動觸發 HTTP 400 回應。Model validation errors automatically trigger an HTTP 400 response. 因此,您的動作將不再需要下列程式碼:Consequently, the following code becomes unnecessary in your actions:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

使用 InvalidModelStateResponseFactory 可自訂所產生回應的輸出。Use InvalidModelStateResponseFactory to customize the output of the resulting response.

當您的動作可以從模型驗證錯誤復原時,停用預設行為將會有所幫助。Disabling the default behavior is useful when your action can recover from a model validation error. SuppressModelStateInvalidFilter 屬性設定為 true 時,會停用預設行為。The default behavior is disabled when the SuppressModelStateInvalidFilter property is set to true. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_<version_number>); 後,於 Startup.ConfigureServices 中新增下列程式碼:Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_<version_number>);:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;

        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });
services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

使用 2.2 或更新版本的相容性旗標,HTTP 400 回應的預設回應類型為 ValidationProblemDetailsWith a compatibility flag of 2.2 or later, the default response type for HTTP 400 responses is ValidationProblemDetails. ValidationProblemDetails 類型符合 RFC 7807 規格The ValidationProblemDetails type complies with the RFC 7807 specification. SuppressUseValidationProblemDetailsForInvalidModelStateResponses 屬性設定為 true,以改為傳回 SerializableError 的 ASP.NET Core 2.1 錯誤格式。Set the SuppressUseValidationProblemDetailsForInvalidModelStateResponses property to true to instead return the ASP.NET Core 2.1 error format of SerializableError. 將下列程式碼加入 Startup.ConfigureServicesAdd the following code in Startup.ConfigureServices:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options
          .SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
    });

繫結來源參數推斷Binding source parameter inference

繫結來源屬性可定義動作參數值的所在位置。A binding source attribute defines the location at which an action parameter's value is found. 系統提供下列繫結來源屬性:The following binding source attributes exist:

屬性Attribute 繫結來源Binding source
[FromBody][FromBody] 要求本文Request body
[FromForm][FromForm] 要求本文中的表單資料Form data in the request body
[FromHeader][FromHeader] 要求標頭Request header
[FromQuery][FromQuery] 要求查詢字串參數Request query string parameter
[FromRoute][FromRoute] 來自目前要求的路由資料Route data from the current request
[FromServices][FromServices] 作為動作參數插入的要求服務The request service injected as an action parameter

警告

當值可能包含 %2f (也就是 /) 時,請勿使用 [FromRoute]Don't use [FromRoute] when values might contain %2f (that is /). %2f 不會是未逸出的 /%2f won't be unescaped to /. 如果值可能包含 %2f,請使用 [FromQuery]Use [FromQuery] if the value might contain %2f.

不含 [ApiController] 屬性時,即會明確定義繫結來源屬性。Without the [ApiController] attribute, binding source attributes are explicitly defined. 若沒有 [ApiController] 或其他繫結來源屬性 (例如 [FromQuery]),ASP.NET Core 執行階段會嘗試使用複雜物件模型繫結器。Without [ApiController] or other binding source attributes like [FromQuery], the ASP.NET Core runtime attempts to use the complex object model binder. 複雜物件模型繫結器會從值提供者 (具有已定義的順序) 提取資料。The complex object model binder pulls data from value providers (which have a defined order). 例如,「主體模型繫結器」一律是選擇加入的。For instance, the 'body model binder' is always opt in.

在下列範例中,[FromQuery] 屬性表示 discontinuedOnly 參數值是在要求 URL 查詢字串中提供:In the following example, the [FromQuery] attribute indicates that the discontinuedOnly parameter value is provided in the request URL's query string:

[HttpGet]
public async Task<ActionResult<List<Product>>> GetAsync(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = await _repository.GetDiscontinuedProductsAsync();
    }
    else
    {
        products = await _repository.GetProductsAsync();
    }

    return products;
}

系統會依據動作參數的預設資料來源,套用推斷規則。Inference rules are applied for the default data sources of action parameters. 然後,這些規則會設定繫結來源,否則就可能要由您手動將其套用至動作參數。These rules configure the binding sources you're otherwise likely to manually apply to the action parameters. 繫結來源屬性的行為如下所示:The binding source attributes behave as follows:

  • 系統會依據複雜類型參數推斷 [FromBody][FromBody] is inferred for complex type parameters. 如果是任何具有像是 IFormCollectionCancellationToken 等特殊意義的複雜內建類型,則為此規則的例外。An exception to this rule is any complex, built-in type with a special meaning, such as IFormCollection and CancellationToken. 繫結來源推斷程式碼會忽略這些特殊的類型。The binding source inference code ignores those special types. 並不會為像是 stringint 等簡單型別,推斷 [FromBody][FromBody] isn't inferred for simple types such as string or int. 因此,當需要使用該功能時,應為簡單型別使用 [FromBody] 屬性。Therefore, the [FromBody] attribute should be used for simple types when that functionality is needed. 當動作已明確指定多個參數 (透過 [FromBody]) 或推斷為從要求主體繫結時,會擲回例外狀況。When an action has more than one parameter explicitly specified (via [FromBody]) or inferred as bound from the request body, an exception is thrown. 例如,下列動作簽章會造成例外狀況:For example, the following action signatures cause an exception:

    // Don't do this. All of the following actions result in an exception.
    [HttpPost]
    public IActionResult Action1(Product product, 
                                 Order order) => null;
    
    [HttpPost]
    public IActionResult Action2(Product product, 
                                 [FromBody] Order order) => null;
    
    [HttpPost]
    public IActionResult Action3([FromBody] Product product, 
                                 [FromBody] Order order) => null;
    

    注意

    在 ASP.NET Core 2.1 中,集合類型參數 (例如清單與陣列) 不正確地推斷為 [FromQuery]In ASP.NET Core 2.1, collection type parameters such as lists and arrays are incorrectly inferred as [FromQuery]. [FromBody] 應該用於這些參數 (若它們將從要求本文繫結)。[FromBody] should be used for these parameters if they are to be bound from the request body. 此行為在 ASP.NET Core 2.2 或更新版本中已修復,其中集合類型參數預設推斷為從本文繫結。This behavior is fixed in ASP.NET Core 2.2 or later, where collection type parameters are inferred to be bound from the body by default.

  • 為類型 IFormFileIFormFileCollection 的動作參數,推斷 [FromForm][FromForm] is inferred for action parameters of type IFormFile and IFormFileCollection. 而不會依據任何簡單或使用者定義的類型進行推斷。It's not inferred for any simple or user-defined types.

  • 系統會依據符合路由範本參數的任何動作參數名稱,推斷 [FromRoute][FromRoute] is inferred for any action parameter name matching a parameter in the route template. 如果有多個路由符合動作參數,則會將任何路由值視為 [FromRoute]When more than one route matches an action parameter, any route value is considered [FromRoute].

  • 系統會依據任何其他動作參數,推斷 [FromQuery][FromQuery] is inferred for any other action parameters.

SuppressInferBindingSourcesForParameters 屬性設定為 true 時,會停用預設推斷規則。The default inference rules are disabled when the SuppressInferBindingSourcesForParameters property is set to true. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_<version_number>); 後,於 Startup.ConfigureServices 中新增下列程式碼:Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_<version_number>);:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;

        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });
services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

多部分/表單資料要求推斷Multipart/form-data request inference

當動作參數標註了 [FromForm] 屬性時,會推斷 multipart/form-data 要求內容類型。When an action parameter is annotated with the [FromForm] attribute, the multipart/form-data request content type is inferred.

SuppressConsumesConstraintForFormFileParameters 屬性設定為 true 時,會停用預設行為。The default behavior is disabled when the SuppressConsumesConstraintForFormFileParameters property is set to true.

將下列程式碼加入 Startup.ConfigureServicesAdd the following code in Startup.ConfigureServices:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;

        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 後,於 Startup.ConfigureServices 中新增下列程式碼:Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

屬性路由需求Attribute routing requirement

屬性路由已變成必要項目。Attribute routing becomes a requirement. 例如:For example:

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase

無法透過 UseMvc 中所定義的慣例路由Startup.Configure 中的 UseMvcWithDefaultRoute來存取動作。Actions are inaccessible via conventional routes defined in UseMvc or by UseMvcWithDefaultRoute in Startup.Configure.

錯誤狀態碼的問題詳細資料回應Problem details responses for error status codes

在 ASP.NET Core 2.2 或更新版本中,MVC 會將錯誤結果 (具有狀態碼 400 以上 (含) 的結果) 為具有 ProblemDetails 的結果。In ASP.NET Core 2.2 or later, MVC transforms an error result (a result with status code 400 or higher) to a result with ProblemDetails. ProblemDetails 是:ProblemDetails is:

  • RFC 7807 規格為基礎的類型。A type based on the RFC 7807 specification.
  • 標準化格式,用以在 HTTP 回應中指定電腦可讀取的錯誤詳細資料。A standardized format for specifying machine-readable error details in an HTTP response.

請考慮下列控制器動作中的程式碼:Consider the following code in a controller action:

if (product == null)
{
    return NotFound();
}

NotFound 的 HTTP 回應具有 404 狀態碼,並附有 ProblemDetails 本文。The HTTP response for NotFound has a 404 status code with a ProblemDetails body. 例如:For example:

{
    type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
    title: "Not Found",
    status: 404,
    traceId: "0HLHLV31KRN83:00000001"
}

問題詳細資料功能需要 2.2 或更新版本的相容性旗標。The problem details feature requires a compatibility flag of 2.2 or later. SuppressMapClientErrors 屬性設定為 true 時,會停用預設行為。The default behavior is disabled when the SuppressMapClientErrors property is set to true. 將下列程式碼加入 Startup.ConfigureServicesAdd the following code in Startup.ConfigureServices:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;

        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

使用 ClientErrorMapping 屬性可設定 ProblemDetails 回應的內容。Use the ClientErrorMapping property to configure the contents of the ProblemDetails response. 舉例來說,下列程式碼會更新 404 回應的 type 屬性:For example, the following code updates the type property for 404 responses:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;

        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

其他資源Additional resources