使用 ASP.NET Core 建立 Web API

ASP.NET Core 支援使用控制器或使用最少的 API 來建立 Web API。 Web API 中的「控制器」都衍生自類別 ControllerBase。 控制器會根據要求啟動和處置。

本文說明如何使用控制器來處理 Web API 要求。 如需在沒有控制器的情況下建立 Web API 的資訊,請參閱教學課程:使用 ASP.NET Core 建立基本 API

ControllerBase 類別

控制器型 API 由一個或多個衍生自 ControllerBase 的控制器類別組成。 Web API 專案範本會提供入門控制器:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

網頁 API 控制器通常應該衍生自 ControllerBase ,而不是衍生自 ControllerController 衍生自 ControllerBase 並會新增檢視支援,以供處理網頁,而不是 Web API 要求。 如果相同的控制器必須支援檢視和 Web API,請衍生自 Controller

ControllerBase 類別提供許多處理 HTTP 要求的實用屬性和方法。 例如,CreatedAtAction 會傳回 201 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

下表包含 ControllerBase 中的方法範例。

方法 注意
BadRequest 傳回 400 狀態碼。
NotFound 傳回 404 狀態碼。
PhysicalFile 傳回檔案。
TryUpdateModelAsync 叫用模型繫結
TryValidateModel 叫用模型驗證

如需所有可用方法和屬性的清單,請參閱 ControllerBase

屬性

Microsoft.AspNetCore.Mvc 命名空間提供的屬性,可用來設定 Web API 控制器和動作方法的行為。 下列範例會使用屬性來指定支援的 HTTP 動作動詞和任何可能傳回的已知 HTTP 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是一些其他可用的屬性範例。

屬性 備註
[Route] 指定控制器或動作的 URL 模式。
[Bind] 指定模型繫結要包含的前置詞和屬性。
[HttpGet] 識別支援 HTTP GET 動作動詞的動作。
[Consumes] 指定動作所接受的資料類型。
[Produces] 指定動作所傳回的資料類型。

如需包含可用屬性的清單,請參閱 Microsoft.AspNetCore.Mvc 命名空間。

ApiController 屬性

[ApiController] 屬性可以套用至控制器類別,以啟用下列固定的 API 特定行為:

特定控制器上的屬性

[ApiController] 屬性可以套用至特定的控制器,如專案範本中的下列範例所示:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

多個控制器上的屬性

在多個控制站上使用同一屬性的方法之一,就是建立以 [ApiController] 屬性標註的自訂基底控制器類別。 下列範例顯示自訂的基底類別和從其衍生的控制站:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

組件上的屬性

[ApiController] 屬性可以套用至組件。 當 [ApiController] 屬性套用至組件時,組件中的所有控制器都會套用 [ApiController] 屬性。 沒有任何方法可以退出個別控制器。 將組件層級的屬性套用至 Program.cs 檔案:

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

屬性路由需求

[ApiController] 屬性會讓屬性路由需求。 例如:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

無法透過 UseEndpointsUseMvcUseMvcWithDefaultRoute 所定義的慣例路由來存取動作。

HTTP 400 自動回應

[ApiController] 屬性會讓模型驗證錯誤自動觸發 HTTP 400 回應。 因此,動作方法不再需要下列程式碼:

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

ASP.NET Core MVC 會使用 ModelStateInvalidFilter 動作篩選來執行上述檢查。

預設 BadRequest 回應

HTTP 400 回應的預設回應類型為 ValidationProblemDetails。 下列回應本文是序列化類型的範例:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 類型:

  • 會提供機器能夠讀取的格式,以便指定 Web API 回應中的錯誤。
  • 會符合 RFC 7807 規格

若要讓自動回應和自訂回應保持一致,請呼叫 ValidationProblem 方法,而不是 BadRequestValidationProblem 會傳回 ValidationProblemDetails 物件以及自動回應。

記錄自動 400 回應

若要記錄自動 400 回應,請將 InvalidModelStateResponseFactory 委派屬性設定為執行自訂處理。 根據預設,InvalidModelStateResponseFactory 會使用 ProblemDetailsFactory 來建立 ValidationProblemDetails 的執行個體。

下列範例示範如何擷取 ILogger<TCategoryName> 的執行個體,以記錄自動 400 回應的相關資訊:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

停用自動 400 回應

若要停用自動 400 行為,請將 SuppressModelStateInvalidFilter 屬性設定為 true。 請新增下列醒目提示的程式碼:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

繫結來源參數推斷

繫結來源屬性可定義動作參數值的所在位置。 系統提供下列繫結來源屬性:

屬性 繫結來源
[FromBody] 要求本文
[FromForm] 要求本文中的表單資料
[FromHeader] 要求標頭
[FromQuery] 要求查詢字串參數
[FromRoute] 來自目前要求的路由資料
[FromServices] 作為動作參數插入的要求服務
[AsParameters] 方法參數

警告

當值可能包含 %2f (也就是 /) 時,請勿使用 [FromRoute]%2f 不會是未逸出的 /。 如果值可能包含 %2f,請使用 [FromQuery]

若沒有 [ApiController] 屬性或繫結來源屬性 (例如 [FromQuery]),ASP.NET Core 執行階段會嘗試使用複雜物件模型繫結器。 複雜物件模型繫結器會以定義的順序從值提供者提取資料。

在下列範例中,[FromQuery] 屬性表示 discontinuedOnly 參數值是在要求 URL 查詢字串中提供:

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

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 屬性會依據動作參數的預設資料來源套用推斷規則。 這些規則透過將屬性套用至動作參數,讓您不必以手動方式識別的繫結來源。 繫結來源推斷規則的行為如下所示:

  • [FromServices] 會針對已在 DI 容器中註冊的複雜類型參數進行推斷。
  • [FromBody] 會針對未在 DI 容器中註冊的複雜類型參數進行推斷。 如果是任何具有像是 IFormCollectionCancellationToken 等特殊意義的複雜內建類型,則為 [FromBody] 推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。
  • [FromForm] 針對類型 IFormFileIFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。
  • 系統會依據符合路由範本參數的任何動作參數名稱推斷 [FromRoute]。 如果有多個路由符合動作參數,則會將任何路由值視為 [FromRoute]
  • 系統會依據任何其他動作參數推斷 [FromQuery]

FromBody 推斷備註

並不會為像是 stringint 等簡單型別,推斷 [FromBody]。 因此,當需要使用該功能時,應為簡單型別使用 [FromBody] 屬性。

當動作有多個參數從要求主體繫結時,會擲回例外狀況。 例如,下列所有動作方法簽章都會造成例外狀況:

  • 因兩個參數都是複雜類型,而推斷 [FromBody]

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 因為其為複雜類型,所以一個有 [FromBody] 屬性,而推斷另一個。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 兩者均有 [FromBody] 屬性。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

FromServices 推斷附註

將類型設定為服務時,參數繫結會透過相依性插入來繫結參數。 這表示不需要將 [FromServices] 屬性明確套用至參數。 在下列程式碼中,這兩個動作都會傳回時間:

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    public ActionResult GetWithAttribute([FromServices] IDateTime dateTime) 
                                                        => Ok(dateTime.Now);

    [Route("noAttribute")]
    public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now);
}

在少數情況下,自動 DI 可能會中斷應用程式,這些應用程式在 DI 中有 API 控制器動作方法也接受的類型。 在 DI 擁有類型並作為 API 控制器動作中的引數並不常見。

若要停用單一動作參數的 [FromServices] 推斷,請將所需的繫結來源屬性套用至參數。 例如,將 [FromBody] 屬性套用至應該從要求本文繫結的動作參數。

若要全域停用 [FromServices] 推斷,請將 DisableImplicitFromServicesParameters 設定為 true

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddSingleton<IDateTime, SystemDateTime>();

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

var app = builder.Build();

app.MapControllers();

app.Run();

透過 IServiceProviderIsService 在應用程式啟動時檢查類型,以判斷 API 控制器動作中的引數是否來自 DI 或其他來源。

推斷 API 控制器動作參數繫結來源的機制會使用下列規則:

停用推斷規則

若要停用繫結來源推斷,請將 SuppressInferBindingSourcesForParameters 設定為 true

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

多部分/表單資料要求推斷

[ApiController] 屬性會針對類型為 IFormFileIFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 multipart/form-data 要求內容類型。

若要停用預設行為,請將 SuppressConsumesConstraintForFormFileParameters 屬性設定為 true

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

錯誤狀態碼的問題詳細資料

MVC 會將錯誤結果 (具有狀態碼 400 以上 (含) 的結果) 為具有 ProblemDetails 的結果。 以 RFC 7807 規格為基礎的 ProblemDetails 類型,在 HTTP 回應中提供電腦可讀取的錯誤詳細資料。

請考慮下列控制器動作中的程式碼:

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

NotFound 方法會產生具有 ProblemDetails 本文的 HTTP 404 狀態碼。 例如:

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

停用 ProblemDetails 回應

SuppressMapClientErrors 屬性設定為 true 時,系統會停用自動為錯誤狀態碼建立 ProblemDetails 的動作。 新增下列程式碼:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

使用 [Consumes] 屬性定義支援的要求內容類型

根據預設,動作會支援所有可用的要求內容類型。 例如,如果應用程式設定為同時支援 JSON 和 XML 輸入格式器,則動作會支援多個內容類型,包括 application/jsonapplication/xml

[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes] 屬性套用至動作或控制器,並指定一或多個內容類型:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

在上述程式碼中,CreateProduct 動作會指定內容類型 application/xml。 路由傳送至此動作的要求必須指定 application/xmlContent-Type 標頭。 未指定 application/xmlContent-Type 標頭的要求會產生 415 不支援的媒體類型回應。

[Consumes] 屬性也可讓動作藉由套用類型條件約束,以根據傳入要求的內容類型來影響其選取範圍。 請考慮下列範例:

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

在上述程式碼中,ConsumesController 會設定為處理傳送至 https://localhost:5001/api/Consumes URL 的要求。 控制器的動作 PostJsonPostForm 都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes] 屬性,系統便會擲回模棱兩可的比對例外狀況。

[Consumes] 屬性會套用至這兩個動作。 PostJson 動作會處理以 application/jsonContent-Type 標頭傳送的要求。 PostForm 動作會處理以 application/x-www-form-urlencodedContent-Type 標頭傳送的要求。

其他資源

ASP.NET Core 支援使用控制器或使用最少的 API 來建立 Web API。 Web API 中的「控制器」都衍生自類別 ControllerBase。 本文說明如何使用控制器來處理 Web API 要求。 如需在沒有控制器的情況下建立 Web API 的資訊,請參閱教學課程:使用 ASP.NET Core 建立基本 API

ControllerBase 類別

控制器型 API 由一個或多個衍生自 ControllerBase 的控制器類別組成。 Web API 專案範本會提供入門控制器:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

網頁 API 控制器通常應該衍生自 ControllerBase ,而不是衍生自 ControllerController 衍生自 ControllerBase 並會新增檢視支援,以供處理網頁,而不是 Web API 要求。 如果相同的控制器必須支援檢視和 Web API,請衍生自 Controller

ControllerBase 類別提供許多處理 HTTP 要求的實用屬性和方法。 例如,CreatedAtAction 會傳回 201 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

下表包含 ControllerBase 中的方法範例。

方法 注意
BadRequest 傳回 400 狀態碼。
NotFound 傳回 404 狀態碼。
PhysicalFile 傳回檔案。
TryUpdateModelAsync 叫用模型繫結
TryValidateModel 叫用模型驗證

如需所有可用方法和屬性的清單,請參閱 ControllerBase

屬性

Microsoft.AspNetCore.Mvc 命名空間提供的屬性,可用來設定 Web API 控制器和動作方法的行為。 下列範例會使用屬性來指定支援的 HTTP 動作動詞和任何可能傳回的已知 HTTP 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是一些其他可用的屬性範例。

屬性 備註
[Route] 指定控制器或動作的 URL 模式。
[Bind] 指定模型繫結要包含的前置詞和屬性。
[HttpGet] 識別支援 HTTP GET 動作動詞的動作。
[Consumes] 指定動作所接受的資料類型。
[Produces] 指定動作所傳回的資料類型。

如需包含可用屬性的清單,請參閱 Microsoft.AspNetCore.Mvc 命名空間。

ApiController 屬性

[ApiController] 屬性可以套用至控制器類別,以啟用下列固定的 API 特定行為:

特定控制器上的屬性

[ApiController] 屬性可以套用至特定的控制器,如專案範本中的下列範例所示:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

多個控制器上的屬性

在多個控制站上使用同一屬性的方法之一,就是建立以 [ApiController] 屬性標註的自訂基底控制器類別。 下列範例顯示自訂的基底類別和從其衍生的控制站:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

組件上的屬性

[ApiController] 屬性可以套用至組件。 當 [ApiController] 屬性套用至組件時,組件中的所有控制器都會套用 [ApiController] 屬性。 沒有任何方法可以退出個別控制器。 將組件層級的屬性套用至 Program.cs 檔案:

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

屬性路由需求

[ApiController] 屬性會讓屬性路由需求。 例如:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

無法透過 UseEndpointsUseMvcUseMvcWithDefaultRoute 所定義的慣例路由來存取動作。

HTTP 400 自動回應

[ApiController] 屬性會讓模型驗證錯誤自動觸發 HTTP 400 回應。 因此,動作方法不再需要下列程式碼:

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

ASP.NET Core MVC 會使用 ModelStateInvalidFilter 動作篩選來執行上述檢查。

預設 BadRequest 回應

下列回應本文是序列化類型的範例:

{
  "": [
    "A non-empty request body is required."
  ]
}

HTTP 400 回應的預設回應類型為 ValidationProblemDetails。 下列回應本文是序列化類型的範例:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 類型:

  • 會提供機器能夠讀取的格式,以便指定 Web API 回應中的錯誤。
  • 會符合 RFC 7807 規格

若要讓自動回應和自訂回應保持一致,請呼叫 ValidationProblem 方法,而不是 BadRequestValidationProblem 會傳回 ValidationProblemDetails 物件以及自動回應。

記錄自動 400 回應

若要記錄自動 400 回應,請將 InvalidModelStateResponseFactory 委派屬性設定為執行自訂處理。 根據預設,InvalidModelStateResponseFactory 會使用 ProblemDetailsFactory 來建立 ValidationProblemDetails 的執行個體。

下列範例示範如何擷取 ILogger<TCategoryName> 的執行個體,以記錄自動 400 回應的相關資訊:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

停用自動 400 回應

若要停用自動 400 行為,請將 SuppressModelStateInvalidFilter 屬性設定為 true。 請新增下列醒目提示的程式碼:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

繫結來源參數推斷

繫結來源屬性可定義動作參數值的所在位置。 系統提供下列繫結來源屬性:

屬性 繫結來源
[FromBody] 要求本文
[FromForm] 要求本文中的表單資料
[FromHeader] 要求標頭
[FromQuery] 要求查詢字串參數
[FromRoute] 來自目前要求的路由資料
[FromServices] 作為動作參數插入的要求服務

警告

當值可能包含 %2f (也就是 /) 時,請勿使用 [FromRoute]%2f 不會是未逸出的 /。 如果值可能包含 %2f,請使用 [FromQuery]

若沒有 [ApiController] 屬性或繫結來源屬性 (例如 [FromQuery]),ASP.NET Core 執行階段會嘗試使用複雜物件模型繫結器。 複雜物件模型繫結器會以定義的順序從值提供者提取資料。

在下列範例中,[FromQuery] 屬性表示 discontinuedOnly 參數值是在要求 URL 查詢字串中提供:

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

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 屬性會依據動作參數的預設資料來源套用推斷規則。 這些規則透過將屬性套用至動作參數,讓您不必以手動方式識別的繫結來源。 繫結來源推斷規則的行為如下所示:

  • [FromBody] 會針對未在 DI 容器中註冊的複雜類型參數進行推斷。 如果是任何具有像是 IFormCollectionCancellationToken 等特殊意義的複雜內建類型,則為 [FromBody] 推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。
  • [FromForm] 針對類型 IFormFileIFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。
  • 系統會依據符合路由範本參數的任何動作參數名稱推斷 [FromRoute]。 如果有多個路由符合動作參數,則會將任何路由值視為 [FromRoute]
  • 系統會依據任何其他動作參數推斷 [FromQuery]

FromBody 推斷備註

並不會為像是 stringint 等簡單型別,推斷 [FromBody]。 因此,當需要使用該功能時,應為簡單型別使用 [FromBody] 屬性。

當動作有多個參數從要求主體繫結時,會擲回例外狀況。 例如,下列所有動作方法簽章都會造成例外狀況:

  • 因兩個參數都是複雜類型,而推斷 [FromBody]

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 因為其為複雜類型,所以一個有 [FromBody] 屬性,而推斷另一個。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 兩者均有 [FromBody] 屬性。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

停用推斷規則

若要停用繫結來源推斷,請將 SuppressInferBindingSourcesForParameters 設定為 true

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

多部分/表單資料要求推斷

[ApiController] 屬性會針對類型為 IFormFileIFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 multipart/form-data 要求內容類型。

若要停用預設行為,請將 SuppressConsumesConstraintForFormFileParameters 屬性設定為 true

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

錯誤狀態碼的問題詳細資料

MVC 會將錯誤結果 (具有狀態碼 400 以上 (含) 的結果) 為具有 ProblemDetails 的結果。 以 RFC 7807 規格為基礎的 ProblemDetails 類型,在 HTTP 回應中提供電腦可讀取的錯誤詳細資料。

請考慮下列控制器動作中的程式碼:

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

NotFound 方法會產生具有 ProblemDetails 本文的 HTTP 404 狀態碼。 例如:

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

停用 ProblemDetails 回應

SuppressMapClientErrors 屬性設定為 true 時,系統會停用自動為錯誤狀態碼建立 ProblemDetails 的動作:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

使用 [Consumes] 屬性定義支援的要求內容類型

根據預設,動作會支援所有可用的要求內容類型。 例如,如果應用程式設定為同時支援 JSON 和 XML 輸入格式器,則動作會支援多個內容類型,包括 application/jsonapplication/xml

[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes] 屬性套用至動作或控制器,並指定一或多個內容類型:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

在上述程式碼中,CreateProduct 動作會指定內容類型 application/xml。 路由傳送至此動作的要求必須指定 application/xmlContent-Type 標頭。 未指定 application/xmlContent-Type 標頭的要求會產生 415 不支援的媒體類型回應。

[Consumes] 屬性也可讓動作藉由套用類型條件約束,以根據傳入要求的內容類型來影響其選取範圍。 請考慮下列範例:

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

在上述程式碼中,ConsumesController 會設定為處理傳送至 https://localhost:5001/api/Consumes URL 的要求。 控制器的動作 PostJsonPostForm 都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes] 屬性,系統便會擲回模棱兩可的比對例外狀況。

[Consumes] 屬性會套用至這兩個動作。 PostJson 動作會處理以 application/jsonContent-Type 標頭傳送的要求。 PostForm 動作會處理以 application/x-www-form-urlencodedContent-Type 標頭傳送的要求。

其他資源

ASP.NET Core 支援使用 C# 建立 RESTful 服務,也稱為 Web API。 若要處理要求,Web API 會使用控制器。 Web API 中的「控制器」都衍生自類別 ControllerBase。 本文說明如何使用控制器來處理 Web API 要求。

檢視或下載範例程式碼。 (如何下載)。

ControllerBase 類別

Web API 由一或多個衍生自 ControllerBase 的控制器類別組成。 Web API 專案範本會提供入門控制器:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

不要透過從 Controller 類別衍生的方式來建立 Web API 控制器。 Controller 衍生自 ControllerBase 並會新增檢視支援,以供處理網頁,而不是 Web API 要求。 此規則的例外:如果您打算為檢視和 Web API 使用相同的控制器,請從 Controller 衍生該控制器。

ControllerBase 類別提供許多處理 HTTP 要求的實用屬性和方法。 例如,ControllerBase.CreatedAtAction 會傳回 201 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是 ControllerBase 提供的一些其他方法範例。

方法 注意
BadRequest 傳回 400 狀態碼。
NotFound 傳回 404 狀態碼。
PhysicalFile 傳回檔案。
TryUpdateModelAsync 叫用模型繫結
TryValidateModel 叫用模型驗證

如需所有可用方法和屬性的清單,請參閱 ControllerBase

屬性

Microsoft.AspNetCore.Mvc 命名空間提供的屬性,可用來設定 Web API 控制器和動作方法的行為。 下列範例會使用屬性來指定支援的 HTTP 動作動詞和任何可能傳回的已知 HTTP 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是一些其他可用的屬性範例。

屬性 備註
[Route] 指定控制器或動作的 URL 模式。
[Bind] 指定模型繫結要包含的前置詞和屬性。
[HttpGet] 識別支援 HTTP GET 動作動詞的動作。
[Consumes] 指定動作所接受的資料類型。
[Produces] 指定動作所傳回的資料類型。

如需包含可用屬性的清單,請參閱 Microsoft.AspNetCore.Mvc 命名空間。

ApiController 屬性

[ApiController] 屬性可以套用至控制器類別,以啟用下列固定的 API 特定行為:

特定控制器上的屬性

[ApiController] 屬性可以套用至特定的控制器,如專案範本中的下列範例所示:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

多個控制器上的屬性

在多個控制站上使用同一屬性的方法之一,就是建立以 [ApiController] 屬性標註的自訂基底控制器類別。 下列範例顯示自訂的基底類別和從其衍生的控制站:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

組件上的屬性

[ApiController] 屬性可以套用至組件。 以這種方式標註會將 Web API 行為套用至組件中的所有控制器。 沒有任何方法可以退出個別控制器。 將組件層級的屬性套用至 Startup 類別周圍的命名空間宣告:

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

屬性路由需求

[ApiController] 屬性會讓屬性路由需求。 例如:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

無法透過 Startup.Configure 中的 UseEndpointsUseMvcUseMvcWithDefaultRoute 所定義的慣例路由來存取動作。

HTTP 400 自動回應

[ApiController] 屬性會讓模型驗證錯誤自動觸發 HTTP 400 回應。 因此,動作方法不再需要下列程式碼:

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

ASP.NET Core MVC 會使用 ModelStateInvalidFilter 動作篩選來執行上述檢查。

預設 BadRequest 回應

下列要求本文是序列化類型的範例:

{
  "": [
    "A non-empty request body is required."
  ]
}

HTTP 400 回應的預設回應類型為 ValidationProblemDetails。 下列要求本文是序列化類型的範例:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 類型:

  • 會提供機器能夠讀取的格式,以便指定 Web API 回應中的錯誤。
  • 會符合 RFC 7807 規格

若要讓自動回應和自訂回應保持一致,請呼叫 ValidationProblem 方法,而不是 BadRequestValidationProblem 會傳回 ValidationProblemDetails 物件以及自動回應。

記錄自動 400 回應

若要記錄自動 400 回應,請將 InvalidModelStateResponseFactory 委派屬性設定為在 Startup.ConfigureServices 中執行自訂處理。 根據預設,InvalidModelStateResponseFactory 會使用 ProblemDetailsFactory 來建立 ValidationProblemDetails 的執行個體。

下列範例示範如何擷取 ILogger<TCategoryName> 的執行個體,以記錄自動 400 回應的相關資訊:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Startup>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails response.
            // To produce a custom response, return a different implementation of IActionResult instead.
            return builtInFactory(context);
        };
    });

停用自動 400 回應

若要停用自動 400 行為,請將 SuppressModelStateInvalidFilter 屬性設定為 true。 在 Startup.ConfigureServices 中新增下列醒目提示的程式碼:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

繫結來源參數推斷

繫結來源屬性可定義動作參數值的所在位置。 系統提供下列繫結來源屬性:

屬性 繫結來源
[FromBody] 要求本文
[FromForm] 要求本文中的表單資料
[FromHeader] 要求標頭
[FromQuery] 要求查詢字串參數
[FromRoute] 來自目前要求的路由資料
[FromServices] 作為動作參數插入的要求服務

警告

當值可能包含 %2f (也就是 /) 時,請勿使用 [FromRoute]%2f 不會是未逸出的 /。 如果值可能包含 %2f,請使用 [FromQuery]

若沒有 [ApiController] 屬性或繫結來源屬性 (例如 [FromQuery]),ASP.NET Core 執行階段會嘗試使用複雜物件模型繫結器。 複雜物件模型繫結器會以定義的順序從值提供者提取資料。

在下列範例中,[FromQuery] 屬性表示 discontinuedOnly 參數值是在要求 URL 查詢字串中提供:

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

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 屬性會依據動作參數的預設資料來源套用推斷規則。 這些規則透過將屬性套用至動作參數,讓您不必以手動方式識別的繫結來源。 繫結來源推斷規則的行為如下所示:

  • 系統會依據複雜類型參數推斷 [FromBody]。 如果是任何具有像是 IFormCollectionCancellationToken 等特殊意義的複雜內建類型,則為 [FromBody] 推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。
  • [FromForm] 針對類型 IFormFileIFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。
  • 系統會依據符合路由範本參數的任何動作參數名稱推斷 [FromRoute]。 如果有多個路由符合動作參數,則會將任何路由值視為 [FromRoute]
  • 系統會依據任何其他動作參數推斷 [FromQuery]

FromBody 推斷備註

並不會為像是 stringint 等簡單型別,推斷 [FromBody]。 因此,當需要使用該功能時,應為簡單型別使用 [FromBody] 屬性。

當動作有多個參數從要求主體繫結時,會擲回例外狀況。 例如,下列所有動作方法簽章都會造成例外狀況:

  • 因兩個參數都是複雜類型,而推斷 [FromBody]

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 因為其為複雜類型,所以一個有 [FromBody] 屬性,而推斷另一個。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 兩者均有 [FromBody] 屬性。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

停用推斷規則

若要停用繫結來源推斷,請將 SuppressInferBindingSourcesForParameters 設定為 true。 將下列程式碼加入 Startup.ConfigureServices

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

多部分/表單資料要求推斷

[ApiController] 屬性會針對類型為 IFormFileIFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 multipart/form-data 要求內容類型。

若要停用預設行為,請在 Startup.ConfigureServices 中將 SuppressConsumesConstraintForFormFileParameters 屬性設定為 true

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

錯誤狀態碼的問題詳細資料

MVC 會將錯誤結果 (具有狀態碼 400 以上 (含) 的結果) 為具有 ProblemDetails 的結果。 以 RFC 7807 規格為基礎的 ProblemDetails 類型,在 HTTP 回應中提供電腦可讀取的錯誤詳細資料。

請考慮下列控制器動作中的程式碼:

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

NotFound 方法會產生具有 ProblemDetails 本文的 HTTP 404 狀態碼。 例如:

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

停用 ProblemDetails 回應

SuppressMapClientErrors 屬性設定為 true 時,系統會停用自動為錯誤狀態碼建立 ProblemDetails 的動作。 將下列程式碼加入 Startup.ConfigureServices

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

使用 [Consumes] 屬性定義支援的要求內容類型

根據預設,動作會支援所有可用的要求內容類型。 例如,如果應用程式設定為同時支援 JSON 和 XML 輸入格式器,則動作會支援多個內容類型,包括 application/jsonapplication/xml

[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes] 屬性套用至動作或控制器,並指定一或多個內容類型:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

在上述程式碼中,CreateProduct 動作會指定內容類型 application/xml。 路由傳送至此動作的要求必須指定 application/xmlContent-Type 標頭。 未指定 application/xmlContent-Type 標頭的要求會產生 415 不支援的媒體類型回應。

[Consumes] 屬性也可讓動作藉由套用類型條件約束,以根據傳入要求的內容類型來影響其選取範圍。 請考慮下列範例:

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

在上述程式碼中,ConsumesController 會設定為處理傳送至 https://localhost:5001/api/Consumes URL 的要求。 控制器的動作 PostJsonPostForm 都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes] 屬性,系統便會擲回模棱兩可的比對例外狀況。

[Consumes] 屬性會套用至這兩個動作。 PostJson 動作會處理以 application/jsonContent-Type 標頭傳送的要求。 PostForm 動作會處理以 application/x-www-form-urlencodedContent-Type 標頭傳送的要求。

其他資源

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

不要透過從 Controller 類別衍生的方式來建立 Web API 控制器。 Controller 衍生自 ControllerBase 並會新增檢視支援,以供處理網頁,而不是 Web API 要求。 此規則的例外:如果您打算為檢視和 Web API 使用相同的控制器,請從 Controller 衍生該控制器。 ControllerBase 類別提供許多處理 HTTP 要求的實用屬性和方法。 例如,ControllerBase.CreatedAtAction 會傳回 201 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是 ControllerBase 提供的一些其他方法範例:

方法 注意
BadRequest 傳回 400 狀態碼。
NotFound 傳回 404 狀態碼。
PhysicalFile 傳回檔案。
TryUpdateModelAsync 叫用模型繫結
TryValidateModel 叫用模型驗證

如需所有可用方法和屬性的清單,請參閱 ControllerBase

屬性

Microsoft.AspNetCore.Mvc 命名空間提供的屬性,可用來設定 Web API 控制器和動作方法的行為。 下列範例會使用屬性來指定支援的 HTTP 動作動詞和任何可能傳回的已知 HTTP 狀態碼:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

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

以下是一些其他可用的屬性範例:

屬性 備註
[Route] 指定控制器或動作的 URL 模式。
[Bind] 指定模型繫結要包含的前置詞和屬性。
[HttpGet] 識別支援 HTTP GET 動作動詞的動作。
[Consumes] 指定動作所接受的資料類型。
[Produces] 指定動作所傳回的資料類型。

如需包含可用屬性的清單,請參閱 Microsoft.AspNetCore.Mvc 命名空間。

ApiController 屬性

[ApiController] 屬性可以套用至控制器類別,以啟用下列固定的 API 特定行為:

特定控制器上的屬性

[ApiController] 屬性可以套用至特定的控制器,如專案範本中的下列範例所示:

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

多個控制器上的屬性

在多個控制站上使用同一屬性的方法之一,就是建立以 [ApiController] 屬性標註的自訂基底控制器類別。 下列範例顯示自訂的基底類別和從其衍生的控制站:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("api/[controller]")]
public class PetsController : MyControllerBase

組件上的屬性

如果相容性版本設定為 2.2 或更新版本,[ApiController] 屬性就可以套用至組件。 以這種方式標註會將 Web API 行為套用至組件中的所有控制器。 沒有任何方法可以退出個別控制器。 將組件層級的屬性套用至 Startup 類別周圍的命名空間宣告:

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

屬性路由需求

[ApiController] 屬性會讓屬性路由需求。 例如:

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

無法透過 UseMvc 中所定義的慣例路由Startup.Configure 中的 UseMvcWithDefaultRoute 來存取動作。

HTTP 400 自動回應

[ApiController] 屬性會讓模型驗證錯誤自動觸發 HTTP 400 回應。 因此,動作方法不再需要下列程式碼:

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

ASP.NET Core MVC 會使用 ModelStateInvalidFilter 動作篩選來執行上述檢查。

預設 BadRequest 回應

使用 2.1 的相容性版本時,HTTP 400 回應的預設回應類型為 SerializableError。 下列要求本文是序列化類型的範例:

{
  "": [
    "A non-empty request body is required."
  ]
}

使用 2.2 或更新版本的相容性版本時,HTTP 400 回應的預設回應類型為 ValidationProblemDetails。 下列要求本文是序列化類型的範例:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

ValidationProblemDetails 類型:

  • 會提供機器能夠讀取的格式,以便指定 Web API 回應中的錯誤。
  • 會符合 RFC 7807 規格

若要讓自動回應和自訂回應保持一致,請呼叫 ValidationProblem 方法,而不是 BadRequestValidationProblem 會傳回 ValidationProblemDetails 物件以及自動回應。

記錄自動 400 回應

請參閱如何在模型驗證錯誤上記錄自動 400 回應 (dotnet/AspNetCore.Docs#12157)

停用自動 400 回應

若要停用自動 400 行為,請將 SuppressModelStateInvalidFilter 屬性設定為 true。 在 Startup.ConfigureServices 中新增下列醒目提示的程式碼:

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

繫結來源參數推斷

繫結來源屬性可定義動作參數值的所在位置。 系統提供下列繫結來源屬性:

屬性 繫結來源
[FromBody] 要求本文
[FromForm] 要求本文中的表單資料
[FromHeader] 要求標頭
[FromQuery] 要求查詢字串參數
[FromRoute] 來自目前要求的路由資料
[FromServices] 作為動作參數插入的要求服務

警告

當值可能包含 %2f (也就是 /) 時,請勿使用 [FromRoute]%2f 不會是未逸出的 /。 如果值可能包含 %2f,請使用 [FromQuery]。 若沒有 [ApiController] 屬性或繫結來源屬性 (例如 [FromQuery]),ASP.NET Core 執行階段會嘗試使用複雜物件模型繫結器。 複雜物件模型繫結器會以定義的順序從值提供者提取資料。

在下列範例中,[FromQuery] 屬性表示 discontinuedOnly 參數值是在要求 URL 查詢字串中提供:

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

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

[ApiController] 屬性會依據動作參數的預設資料來源套用推斷規則。 這些規則透過將屬性套用至動作參數,讓您不必以手動方式識別的繫結來源。 繫結來源推斷規則的行為如下所示:

  • 系統會依據複雜類型參數推斷 [FromBody]。 如果是任何具有像是 IFormCollectionCancellationToken 等特殊意義的複雜內建類型,則為 [FromBody] 推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。
  • [FromForm] 針對類型 IFormFileIFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。
  • 系統會依據符合路由範本參數的任何動作參數名稱推斷 [FromRoute]。 如果有多個路由符合動作參數,則會將任何路由值視為 [FromRoute]
  • 系統會依據任何其他動作參數推斷 [FromQuery]

FromBody 推斷備註

並不會為像是 stringint 等簡單型別,推斷 [FromBody]。 因此,當需要使用該功能時,應為簡單型別使用 [FromBody] 屬性。

當動作有多個參數從要求主體繫結時,會擲回例外狀況。 例如,下列所有動作方法簽章都會造成例外狀況:

  • 因兩個參數都是複雜類型,而推斷 [FromBody]

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • 因為其為複雜類型,所以一個有 [FromBody] 屬性,而推斷另一個。

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • 兩者均有 [FromBody] 屬性。

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

注意

在 ASP.NET Core 2.1 中,集合類型參數 (例如清單與陣列) 不正確地推斷為 [FromQuery][FromBody] 屬性應該用於這些參數 (若它們將從要求本文繫結)。 此行為在 ASP.NET Core 2.2 或更新版本中已修正,其中集合類型參數預設推斷為從本文繫結。

停用推斷規則

若要停用繫結來源推斷,請將 SuppressInferBindingSourcesForParameters 設定為 true。 將下列程式碼加入 Startup.ConfigureServices

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

多部分/表單資料要求推斷

[ApiController] 屬性會針對類型為 IFormFileIFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 multipart/form-data 要求內容類型。 若要停用預設行為,請在 Startup.ConfigureServices 中將 SuppressConsumesConstraintForFormFileParameters 屬性設定為 true

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

錯誤狀態碼的問題詳細資料

當相容性版本為 2.2 或更新版本時,MVC 會將錯誤結果 (具有狀態碼 400 以上的結果) 為具有 ProblemDetails 的結果。 以 RFC 7807 規格為基礎的 ProblemDetails 類型,在 HTTP 回應中提供電腦可讀取的錯誤詳細資料。 請考慮下列控制器動作中的程式碼:

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

NotFound 方法會產生具有 ProblemDetails 本文的 HTTP 404 狀態碼。 例如:

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

停用 ProblemDetails 回應

SuppressMapClientErrors 屬性設定為 true 時,系統會停用自動為錯誤狀態碼建立 ProblemDetails 的動作。 將下列程式碼加入 Startup.ConfigureServices

使用 [Consumes] 屬性定義支援的要求內容類型

根據預設,動作會支援所有可用的要求內容類型。 例如,如果應用程式設定為同時支援 JSON 和 XML 輸入格式器,則動作會支援多個內容類型,包括 application/jsonapplication/xml

[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes] 屬性套用至動作或控制器,並指定一或多個內容類型:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

在上述程式碼中,CreateProduct 動作會指定內容類型 application/xml。 路由傳送至此動作的要求必須指定 application/xmlContent-Type 標頭。 未指定 application/xmlContent-Type 標頭的要求會產生 415 不支援的媒體類型回應。 [Consumes] 屬性也可讓動作藉由套用類型條件約束,以根據傳入要求的內容類型來影響其選取範圍。 請考慮下列範例:

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

在上述程式碼中,ConsumesController 會設定為處理傳送至 https://localhost:5001/api/Consumes URL 的要求。 控制器的動作 PostJsonPostForm 都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes] 屬性,系統便會擲回模棱兩可的比對例外狀況。 [Consumes] 屬性會套用至這兩個動作。 PostJson 動作會處理以 application/jsonContent-Type 標頭傳送的要求。 PostForm 動作會處理以 application/x-www-form-urlencodedContent-Type 標頭傳送的要求。

其他資源