使用 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 ,而不是衍生自 Controller。 Controller
衍生自 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
無法透過 UseEndpoints
、UseMvc 或 UseMvcWithDefaultRoute 所定義的慣例路由來存取動作。
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 方法,而不是 BadRequest。 ValidationProblem
會傳回 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 容器中註冊的複雜類型參數進行推斷。 如果是任何具有像是 IFormCollection 與 CancellationToken 等特殊意義的複雜內建類型,則為[FromBody]
推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。[FromForm]
針對類型 IFormFile 與 IFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。- 系統會依據符合路由範本參數的任何動作參數名稱推斷
[FromRoute]
。 如果有多個路由符合動作參數,則會將任何路由值視為[FromRoute]
。 - 系統會依據任何其他動作參數推斷
[FromQuery]
。
FromBody 推斷備註
並不會為像是 string
或 int
等簡單型別,推斷 [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 控制器動作參數繫結來源的機制會使用下列規則:
- 先前指定的
BindingInfo.BindingSource
永遠不會被覆寫。 - 在 DI 容器中註冊的複雜類型參數會被指派
BindingSource.Services
。 - 未在 DI 容器中註冊的複雜類型參數會被指派
BindingSource.Body
。 - 在任何路由範本中名稱呈現為路由值的參數會被指派
BindingSource.Path
。 - 所有其他參數都是
BindingSource.Query
。
停用推斷規則
若要停用繫結來源推斷,請將 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]
屬性會針對類型為 IFormFile 和 IFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 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/json
和 application/xml
。
[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes]
屬性套用至動作或控制器,並指定一或多個內容類型:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
在上述程式碼中,CreateProduct
動作會指定內容類型 application/xml
。 路由傳送至此動作的要求必須指定 application/xml
的 Content-Type
標頭。 未指定 application/xml
的 Content-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 的要求。 控制器的動作 PostJson
和 PostForm
都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes]
屬性,系統便會擲回模棱兩可的比對例外狀況。
[Consumes]
屬性會套用至這兩個動作。 PostJson
動作會處理以 application/json
的 Content-Type
標頭傳送的要求。 PostForm
動作會處理以 application/x-www-form-urlencoded
的 Content-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 ,而不是衍生自 Controller。 Controller
衍生自 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
無法透過 UseEndpoints
、UseMvc 或 UseMvcWithDefaultRoute 所定義的慣例路由來存取動作。
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 方法,而不是 BadRequest。 ValidationProblem
會傳回 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 容器中註冊的複雜類型參數進行推斷。 如果是任何具有像是 IFormCollection 與 CancellationToken 等特殊意義的複雜內建類型,則為[FromBody]
推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。[FromForm]
針對類型 IFormFile 與 IFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。- 系統會依據符合路由範本參數的任何動作參數名稱推斷
[FromRoute]
。 如果有多個路由符合動作參數,則會將任何路由值視為[FromRoute]
。 - 系統會依據任何其他動作參數推斷
[FromQuery]
。
FromBody 推斷備註
並不會為像是 string
或 int
等簡單型別,推斷 [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]
屬性會針對類型為 IFormFile 和 IFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 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/json
和 application/xml
。
[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes]
屬性套用至動作或控制器,並指定一或多個內容類型:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
在上述程式碼中,CreateProduct
動作會指定內容類型 application/xml
。 路由傳送至此動作的要求必須指定 application/xml
的 Content-Type
標頭。 未指定 application/xml
的 Content-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 的要求。 控制器的動作 PostJson
和 PostForm
都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes]
屬性,系統便會擲回模棱兩可的比對例外狀況。
[Consumes]
屬性會套用至這兩個動作。 PostJson
動作會處理以 application/json
的 Content-Type
標頭傳送的要求。 PostForm
動作會處理以 application/x-www-form-urlencoded
的 Content-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
中的 UseEndpoints
、UseMvc 或 UseMvcWithDefaultRoute 所定義的慣例路由來存取動作。
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 方法,而不是 BadRequest。 ValidationProblem
會傳回 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]
。 如果是任何具有像是 IFormCollection 與 CancellationToken 等特殊意義的複雜內建類型,則為[FromBody]
推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。 [FromForm]
針對類型 IFormFile 與 IFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。- 系統會依據符合路由範本參數的任何動作參數名稱推斷
[FromRoute]
。 如果有多個路由符合動作參數,則會將任何路由值視為[FromRoute]
。 - 系統會依據任何其他動作參數推斷
[FromQuery]
。
FromBody 推斷備註
並不會為像是 string
或 int
等簡單型別,推斷 [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]
屬性會針對類型為 IFormFile 和 IFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 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/json
和 application/xml
。
[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes]
屬性套用至動作或控制器,並指定一或多個內容類型:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
在上述程式碼中,CreateProduct
動作會指定內容類型 application/xml
。 路由傳送至此動作的要求必須指定 application/xml
的 Content-Type
標頭。 未指定 application/xml
的 Content-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 的要求。 控制器的動作 PostJson
和 PostForm
都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes]
屬性,系統便會擲回模棱兩可的比對例外狀況。
[Consumes]
屬性會套用至這兩個動作。 PostJson
動作會處理以 application/json
的 Content-Type
標頭傳送的要求。 PostForm
動作會處理以 application/x-www-form-urlencoded
的 Content-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 特定行為:
- 屬性路由需求
- HTTP 400 自動回應
- 繫結來源參數推斷
- 多部分/表單資料要求推斷
- 錯誤狀態碼的問題詳細資料「錯誤狀態碼的問題詳細資料」功能需要 2.2 或更新版本的相容性版本。 其他功能則需要 2.1 或更新版本的相容性版本。
- 屬性路由需求
- HTTP 400 自動回應
- 繫結來源參數推斷
- 多部分/表單資料要求推斷 這些功能需要 2.1 或更新版本的相容性版本。
特定控制器上的屬性
[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 方法,而不是 BadRequest。 ValidationProblem
會傳回 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]
。 如果是任何具有像是 IFormCollection 與 CancellationToken 等特殊意義的複雜內建類型,則為[FromBody]
推斷規則的例外。 繫結來源推斷程式碼會忽略這些特殊的類型。 [FromForm]
針對類型 IFormFile 與 IFormFileCollection 的動作參數推斷的。 而不會依據任何簡單或使用者定義的類型進行推斷。- 系統會依據符合路由範本參數的任何動作參數名稱推斷
[FromRoute]
。 如果有多個路由符合動作參數,則會將任何路由值視為[FromRoute]
。 - 系統會依據任何其他動作參數推斷
[FromQuery]
。
FromBody 推斷備註
並不會為像是 string
或 int
等簡單型別,推斷 [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]
屬性會針對類型為 IFormFile 和 IFormFileCollection 的動作參數套用推斷規則。 系統會針對這些類型推斷 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/json
和 application/xml
。
[Consumes] 屬性可讓動作限制支援的要求內容類型。 將 [Consumes]
屬性套用至動作或控制器,並指定一或多個內容類型:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
在上述程式碼中,CreateProduct
動作會指定內容類型 application/xml
。 路由傳送至此動作的要求必須指定 application/xml
的 Content-Type
標頭。 未指定 application/xml
的 Content-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 的要求。 控制器的動作 PostJson
和 PostForm
都會使用相同的 URL 來處理 POST 要求。 如果沒有套用類型條件約束的 [Consumes]
屬性,系統便會擲回模棱兩可的比對例外狀況。
[Consumes]
屬性會套用至這兩個動作。 PostJson
動作會處理以 application/json
的 Content-Type
標頭傳送的要求。 PostForm
動作會處理以 application/x-www-form-urlencoded
的 Content-Type
標頭傳送的要求。