public class Todo : IBindableFromHttpContext<Todo>
public static async ValueTask<Todo?> BindAsync(
HttpContext context,
ParameterInfo parameter)
var xmlDoc = await XDocument.LoadAsync(context.Request.Body, LoadOptions.None, context.RequestAborted);
var serializer = new XmlSerializer(typeof(Todo));
return (Todo?)serializer.Deserialize(xmlDoc.CreateReader());
如果端點未定義系結至要求本文的任何參數,請使用 Accepts 擴充方法指定端點接受的內容類型。
如果您指定 Accepts 多次,則只會使用最後一個的元數據-- 它們不會合併。
在基於控制器的應用程式中,產生的 OpenAPI 文件中請求主體的內容類型,是根據綁定於請求主體的參數類型、 InputFormatter 應用程式中設定的型別,或路由 [Consumes] 處理方法中的屬性來決定。
ASP.NET Core 使用 InputFormatter 來反序列化 FromBody 請求主體。
InputFormatters 是在傳遞至應用程式服務集合的MvcOptions擴充方法中AddControllers所設定的。
每個輸入格式化器在其屬性中 SupportedMediaTypes 宣告可處理的內容類型,以及可處理的正體內容類型,並使用其 CanReadType 方法。
ASP.NET Core MVC 內建 JSON 和 XML 的輸入格式化器,但預設僅啟用 JSON 輸入格式化器。
內建的 JSON 輸入格式器支援 application/json、 text/json和 application/*+json 內容類型,而內建的 XML 輸入格式器則支援 application/xml、 text/xml和 application/*+xml 內容類型。
根據預設,FromBody要求本文的內容類型可以是任何InputFormatter參數型別由FromBody接受的內容類型。 對於帶有 FromForm 參數的請求體,預設內容類型為 multipart/form-data 或 application/x-www-form-urlencoded。若路由處理方法未指定屬性, [Consumes] 這些內容類型會包含在生成的 OpenAPI 文件中。
路由處理程序接受的內容類型可以透過端點的 過濾器 (動作範圍)來限制。
屬性 [Consumes] 會將動作範圍篩選新增至端點,以限制路由處理程式將接受的內容類型。
此時,生成的 OpenAPI 文件中的 requestBody 只會包含屬性中 [Consumes] 指定的內容類型。
屬性 [Consumes] 無法新增對沒有相關聯輸入格式子之內容類型的支援,而產生的OpenAPI檔不包含任何沒有相關聯輸入格式子的內容類型。
針對 JSON 或 XML 以外的內容類型,您必須建立自訂輸入格式器。
欲了解更多資訊與範例,請參閱 ASP.NET Core Web API 中的 自訂格式化器。
如果路由處理程式沒有 FromBody 或 FromForm 參數,路由處理程式可能會直接從 Request.Body 數據流讀取要求本文,而且可能會使用 [Consumes] 屬性來限制允許的內容類型,但 OpenAPI 檔中不會產生任何 requestBody。
描述回應類型
OpenAPI 支援提供從 API 傳回的回應描述。 ASP.NET Core 提供多種策略來設定端點的回應元資料。 可設定的回應元資料包括狀態碼、回應主體的類型,以及回應的內容類型。 OpenAPI 中的回應可能會有其他元數據,例如描述、標頭、連結和範例。 可以使用 文件轉換器 或 作業轉換器來設定此額外的中繼資料。
設定回應元數據的特定機制取決於正在開發的應用程式類型。
Produces擴充方法可在端點上指定狀態碼、回應體型態及端點回應的內容類型。
[ProducesResponseType]或 ProducesResponseTypeAttribute<T> 屬性可用來指定響應主體的類型。
路由處理器可用來回傳一個型別,該型別實作 IEndpointMetadataProvider 以指定回應體的型別與內容型別。
ProducesProblem端點上的擴充方法可用來指定錯誤回應的狀態碼與內容類型。
請注意,Produces 和 ProducesProblem 擴充方法於 RouteHandlerBuilder 和 RouteGroupBuilder 都受支援。 例如,這允許針對群組中的所有作業定義一組常見的錯誤回應。
未由上述其中一個策略指定時,:
回應的狀態代碼預設為 200。
回應主體的架構可以從端點方法的隱含或明確傳回類型推斷,例如,從 T 中 Task<TResult>推斷,否則會被視為未指定。
指定或推斷之響應主體的內容類型為 「application/json」。。
在「Minimal API」中,Produces 擴充方法和 [ProducesResponseType] 屬性只會設定端點的回應中繼資料。 它們不會修改或限制端點的行為,其可能會傳回與元數據指定的狀態代碼或響應主體類型不同的狀態代碼或響應主體類型,而且內容類型是由路由處理程式方法的傳回類型所決定,而不論屬性或擴充方法中指定的任何內容類型為何。
擴充 Produces 方法可以指定端點的回應類型,其預設狀態代碼為 200,預設內容類型為 application/json。 下面這個範例可說明這點:
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
[ProducesResponseType]可用來將回應元數據新增至端點。 請注意,屬性是套用在路由處理方法上,而不是應用在建立路由的方法調用上,如下列範例所示:
app.MapGet("/todos",
[ProducesResponseType<List<Todo>>(200)]
async (TodoDb db) => await db.Todos.ToListAsync());
[ProducesResponseType]、 [Produces]和 [ProducesDefaultResponseType] 也支援稱為 的選擇性字串屬性 Description ,可用來描述回應。 這適用於說明客戶端預期特定回應的原因或時機:
app.MapGet("/todos/{id}",
[ProducesResponseType<Todo>(200,
Description = "Returns the requested Todo item.")]
[ProducesResponseType(404, Description = "Requested item not found.")]
[ProducesDefault(Description = "Undocumented status code.")]
async (int id, TodoDb db) => /* Code here */);
在實現端點路由處理器時使用 TypedResults,會自動包含端點回應類型的中繼資料。 例如,下列程式碼會自動以具有 200 內容型別的 application/json 狀態碼的回應來註釋端點。
app.MapGet("/todos", async (TodoDb db) =>
var todos = await db.Todos.ToListAsync();
return TypedResults.Ok(todos);
只有那些實作 IEndpointMetadataProvider 的傳回型別會在 OpenAPI 文件中建立一個 responses 條目。 以下是產生TypedResults項目之responses一些輔助方法的部分清單:
您可以實作 類別來設定端點元數據,並從路由處理程式傳回它。
描述二進位檔案回應
要描述 OpenAPI 文件中回傳二進位檔案回應的端點,請使用 Produces extension 方法,以 type FileContentResult 參數指定回應類型與內容類型:
app.MapPost("/filecontentresult", () =>
var content = "This endpoint returns a FileContentResult!"u8.ToArray();
return TypedResults.File(content);
.Produces<FileContentResult>(contentType: MediaTypeNames.Application.Octet);
這會產生一個具有 type: string 和 format: binary 的 FileContentResult 類型的 OpenAPI 架構。
產生的 OpenAPI 文件描述端點回應如下:
responses:
'200':
description: OK
content:
application/octet-stream:
schema:
$ref: '#/components/schemas/FileContentResult'
其中 FileContentResult 定義為 components/schemas :
components:
schemas:
FileContentResult:
type: string
format: binary
設定 ProblemDetails 的回應
為可能傳回 ProblemDetails 回應的端點設定回應類型時,可以使用下列專案來新增端點的適當回應元數據:
ProducesProblem
ProducesValidationProblem 擴充方法。
TypedResults 的狀態代碼在(400-499)範圍內。
欲了解更多如何配置最小 API 應用程式以回傳 ProblemDetails 回應的資訊,請參見 Handle errors in ASP.NET Core APIs。
多個回應型別
如果端點可以在不同案例中傳回不同的回應型別,您可以透過下列方式提供中繼資料:
多次調用 Produces 擴充方法,如下列範例所示:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
在簽章中使用 Results<TResult1,TResult2,TResult3,TResult4,TResult5,TResult6>,處理常式主體中使用 TypedResults,如下列範例所示:
app.MapGet("/book/{id}", Results<Ok<Book>, NotFound>
(int id, List<Book> bookList) =>
return bookList.FirstOrDefault((i) => i.Id == id) is Book book
? TypedResults.Ok(book)
: TypedResults.NotFound();
Results<TResult1,TResult2,TResultN>
聯合類型聲明路由處理程序會返回多個實作IResult的具體類型,其中任何實作IEndpointMetadataProvider的類型都將為端點的中繼資料做出貢獻。
聯合型別會實作隱含轉換運算子。 這些運算子可讓編譯器自動將泛型引數中指定的型別轉換為聯合型別的實例。 此功能的額外優點是提供編譯時檢查,以確保路由處理常式僅傳回它宣告的結果。 嘗試傳回未宣告為其中一個泛型引數的型別至 Results<TResult1,TResult2,TResultN> 會產生編譯錯誤。
在基於控制器的應用程式中,ASP.NET Core 可以從動作方法簽名、屬性和慣例中擷取回應元資料。
你可以使用 [ProducesResponseType] or ProducesResponseTypeAttribute<T> 屬性來指定狀態碼、回應主體的類型,以及動作方法回應的內容類型。
您可以使用 [Produces] 或 ProducesAttribute<T> 屬性來指定回應主體的類型。
您可以使用 [ProducesDefaultResponseType] 屬性來指定「預設」回應的響應主體類型。
您可以使用 [ProducesErrorResponseType] 屬性來指定錯誤回應的響應主體類型。 不過請注意,這只是補充屬性中 4XX 狀態碼所指定的 [ProducesResponseType] 狀態碼和內容類型。
只有一或 [Produces] 個屬性 ProducesAttribute<T> 可以套用至動作方法,但具有不同狀態代碼的多個 [ProducesResponseType] 或 ProducesResponseTypeAttribute<T> 屬性可以套用至單一動作方法。
上述所有屬性都可以套用至個別動作方法,或套用至控制器中所有動作方法的控制器類別。
[ProducesResponseType]、 [Produces]和 [ProducesDefaultResponseType] 也支援稱為 的選擇性字串屬性 Description ,可用來描述回應。 這適用於說明客戶端預期特定回應的原因或時機:
[HttpGet("/todos/{id}")]
[ProducesResponseType<Todo>(StatusCodes.Status200OK,
"application/json", Description = "Returns the requested Todo item.")]
[ProducesResponseType(StatusCodes.Status404NotFound,
Description = "Requested Todo item not found.")]
[ProducesDefault(Description = "Undocumented status code.")]
public async Task<ActionResult<Todo>> GetTodoItem(string id, Todo todo)
當屬性未指定時:
回應的狀態代碼預設為 200。
2xx 回應的響應正文架構可以從動作方法的返回類型推斷,例如從 T 中的 ActionResult<TValue> 推斷,但在其他情況下則視為未指定。
4xx 回應的回應主體架構被推斷為問題詳細資訊物件。
3xx 和 5xx 回應的響應主體架構被視為未指定。
回應本文的內容類型可以從動作方法的傳回型別和輸出格式器集合推斷。
根據預設,不會進行編譯時間檢查,以確保以 [ProducesResponseType] 屬性 指定的響應元數據與動作方法的實際行為一致,此方法可能會傳回與元數據指定的不同狀態代碼或回應主體類型。 若要啟用這些檢查, 請啟用 Web API 分析器。
在控制器式應用程式中,當模型驗證失敗或動作方法回傳 4xx 或 5xx HTTP 狀態碼時,ASP.NET 會以 ProblemDetails 回應類型。 驗證錯誤通常會使用 400 狀態代碼,因此您可以使用 [ProducesResponseType] 屬性 來指定動作的錯誤回應,如下列範例所示:
[HttpPut("/todos/{id}")]
[ProducesResponseType<Todo>(StatusCodes.Status200OK,
"application/json")]
[ProducesResponseType<Todo>(StatusCodes.Status201Created,
"application/json")]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest,
"application/problem+json")]
public async Task<ActionResult<Todo>> CreateOrReplaceTodo(string id, Todo todo)
此範例也會說明如何定義動作方法的多個回應類型,包括響應主體的內容類型。
描述二進位檔案回應
要描述回傳二進位檔案回應的端點,請使用屬性 [ProducesResponseType<FileContentResult>] 指定回應類型與內容類型:
[HttpPost("filecontentresult")]
[ProducesResponseType<FileContentResult>(StatusCodes.Status200OK, MediaTypeNames.Application.Octet)]
public IActionResult PostFileContentResult()
var content = "This endpoint returns a FileContentResult!"u8.ToArray();
return new FileContentResult(content, MediaTypeNames.Application.Octet);
此操作產生與 Minimal API 二進位檔案回應範例相同的 OpenAPI 描述,定義 FileContentResult 為 type: string 和 format: binary。
從生成的文件中排除端點
根據預設,應用程式中定義的所有端點都會記錄在產生的 OpenAPI 檔案中,但可以使用屬性或擴充方法從檔中排除端點。
指定應排除之端點的機制取決於所開發的應用程式類型。
下列範例示範從產生的 OpenAPI 文件中排除指定端點的不同策略。
app.MapGet("/extension-method", () => "Hello world!")
.ExcludeFromDescription();
app.MapGet("/attributes",
[ExcludeFromDescription]
() => "Hello world!");
在控制器型應用程式中, [ApiExplorerSettings] 屬性可用來從 OpenAPI 檔中排除控制器類別中的端點或所有端點。
下列範例示範如何從產生的 OpenAPI 檔中排除端點:
[HttpGet("/private")]
[ApiExplorerSettings(IgnoreApi = true)]
public IActionResult PrivateEndpoint() {
return Ok("This is a private endpoint");
要求或回應主體中使用的 C# 類別或記錄會以所產生 OpenAPI 文件的結構描表示。
預設情況下,架構中只 public 表示屬性,但也可 JsonSerializerOptions 為欄位建立結構屬性。
當 PropertyNamingPolicy 設定為駝峰箱(這是 ASP.NET 網頁應用程式的預設值),結構中的屬性名稱即為類別或記錄屬性名稱的駝峰箱形式。
[JsonPropertyName] 可用於個別屬性,以指定結構描述中的屬性名稱。
JSON 架構庫會將標準 C# 數值類型對應至 OpenAPItype 和format,根據應用程式中使用的NumberHandlingJsonSerializerOptions屬性。 在 ASP.NET Core Web API 應用程式中,此屬性的預設值為 JsonNumberHandling.AllowReadingFromString。
NumberHandling當 屬性設定為 JsonNumberHandling.AllowReadingFromString時,數值類型會對應如下:
C# 類型
開放API type
開放API format
請注意,在控制器型應用程式中,這些屬性會將篩選新增至作業,以驗證任何傳入的資料是否符合條件約束。 在最小 API 中,這些屬性會在產生的結構描述中設定中繼資料,但必須透過端點篩選、路由處理常式邏輯或透過第三方套件明確執行驗證。
屬性也可以放在記錄定義的參數清單中,但必須包含 property 修飾詞。 例如:
public record Todo(
[property: Required]
[property: Description("The unique identifier for the todo")]
int Id,
[property: Description("The title of the todo")]
[property: MaxLength(120)]
string Title,
[property: Description("Whether the todo has been completed")]
bool Completed
required
在類別、結構或記錄中,具有 [Required] 屬性或 必要 修飾詞的屬性一律位於 required 對應的結構描述中。
您也可以根據類別、結構或記錄的建構函式(隱含和明確)來要求其他屬性。
對於具有單一公用建構函式的類別或記錄類別,在對應的架構中,任何作為建構函式參數且名稱和類型相同的屬性(不區分大小寫比對)都是必需的。
對於具有多個公用建構函式的類別或記錄類別,不需要其他屬性。
對於結構或記錄結構,不需要其他屬性,因為 C# 一律會定義結構的隱含無參數建構函式。
C# 中的列舉類型是以整數為基礎,但可以使用 JSON 中的 [JsonConverter] 和 JsonStringEnumConverter 表示為字串。 當列舉類型在 JSON 中以字串表示時,產生的結構描述將具有列舉字串值的 enum 屬性。
下列範例示範如何使用 JsonStringEnumConverter 來將列舉表示為 JSON 中的字串:
[JsonConverter(typeof(JsonStringEnumConverter<DayOfTheWeekAsString>))]
public enum DayOfTheWeekAsString
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
特殊案例是當列舉類型具有 [Flags] 屬性時,表示列舉可以視為位字段,也就是一組旗標。 具有enum的旗標[JsonConverterAttribute]在生成的架構中被定義為type: string,且沒有enum屬性。 不會產生 enum 任何屬性,因為值可以是列舉值的任何組合。 例如,下列enum可能會有"Pepperoni, Sausage"或"Sausage, Mushrooms, Anchovies"之類的值:
[Flags, JsonConverter(typeof(JsonStringEnumConverter<PizzaToppings>))]
public enum PizzaToppings {
Pepperoni = 1,
Sausage = 2,
Mushrooms = 4,
Anchovies = 8
不含 [JsonConverter] 的列舉類型會在產生的結構描述中定義為 type: integer。
注意:[AllowedValues] 屬性不會設定某個屬性的 enum 值。
全域設定 JSON 選項 會顯示如何全域設定 JsonStringEnumConverter 。
可為 Null
定義為可為 Null 值或參考型別的屬性會在產生的架構中顯示,並使用關鍵字 type,其值為包含 null 作為其中一種型別的陣列。 這與 System.Text.Json 反序列化器的預設行為一致,它接受 null 作為可為 NULL 的屬性的有效值。
例如,定義為 string? 的 C# 屬性會在產生的架構中表示為:
"nullableString": {
"description": "A property defined as string?",
"type": [
"null",
"string"
如果應用程式設定為產生 OpenAPI v3.0 或 OpenAPI v2 檔,則產生的架構中有可為 Null 的值或參考類型 nullable: true ,因為這些 OpenAPI 版本不允許 type 字段成為陣列。
additionalProperties
結構定義預設不會產生 additionalProperties 判斷提示,這表示 true 的預設值。 這與 System.Text.Json 還原序列化程式的預設行為一致,它會默默忽略 JSON 物件中的其他屬性。
如果結構描述的其他屬性應該只有特定類型的值,請將屬性或類別定義為 Dictionary<string, type>。 字典的索引鍵類型必須是 string。 這會產生結構描述,其中 additionalProperties 指定 "type" 的結構描述為必要的實值類型。
使用父類別上的 [JsonPolymorphic] 和 [JsonDerivedType] 屬性來指定多型類型的歧視性字段和子類型。
[JsonDerivedType] 將鑑別子欄位新增到每個子類別的結構模式中,並通過列舉來指定每個子類別的特定鑑別子值。 這個屬性也會修改每個衍生類別的建構函式,以設定鑑別子值。
具有 [JsonPolymorphic] 屬性的抽象類別具有 discriminator 結構描述中的欄位,但具有 [JsonPolymorphic] 屬性的實體類別沒有 discriminator 欄位。 OpenAPI 要求鑑別子屬性是結構描述中的必要屬性,但由於實體基底類別中未定義鑑別子屬性,所以結構描述不能包含 discriminator 欄位。
結構描述轉換器可用來覆寫任何預設的中繼資料,或在生成的結構描述中新增其他中繼資料,例如 example 值。 如需詳細資訊,請參閱使用結構描述轉換器。
全域設定 JSON 串行化選項
下列程式代碼會全域設定一些 JSON 選項,適用於基本 API 和控制器型 API:
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http.Json;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.Configure<JsonOptions>(options =>
options.SerializerOptions.Converters.Add(
new JsonStringEnumConverter<DayOfTheWeekAsString>());
options.SerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
options.SerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.CamelCase;
builder.Services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(
new JsonStringEnumConverter<DayOfTheWeekAsString>());
options.JsonSerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.CamelCase;
var app = builder.Build();
if (app.Environment.IsDevelopment())
app.MapOpenApi();
app.UseHttpsRedirection();
app.MapGet("/", () =>
var day = DayOfTheWeekAsString.Friday;
return Results.Json(day);
app.MapPost("/", (DayOfTheWeekAsString day) =>
return Results.Json($"Received: {day}");
app.UseRouting();
app.MapControllers();
app.Run();
MVC JSON 選項和全域 JSON 選項
下表顯示MVC JSON 選項和全域最小 API JSON 選項之間的主要差異:
ASP.NET 從網頁應用程式的端點收集元資料,並用來產生 OpenAPI 文件。
在控制器型應用程式中,當控制器具有[EndpointDescription]時,會從[HttpPost]、[Produces]和[ApiController]等屬性中收集元數據。
在最小 API 中,元資料可從屬性收集,但也可透過擴充方法及其他策略(如從路由處理器回傳 TypedResults )設定。
下表提供所收集中繼資料的概覽,並說明設定中繼資料的策略。
Metadata
Attribute
ASP.NET Core 也能從 XML 文件註解中收集元資料。 欲了解更多資訊,請參閱ASP.NET Core 中對 ASP.NET Core OpenAPI XML 文件註解支援的詳細資訊。
下列各節示範如何在應用程式中包含中繼資料,以自訂產生的 OpenAPI 文件。
摘要和描述
端點摘要與描述可以使用屬性[EndpointSummary] 和 [EndpointDescription] 設定,或在 Minimal API 中使用擴充方法WithSummary 和 WithDescription 設定。
下列範例示範設定摘要和描述的不同策略。
請注意,屬性置放在委派方法上,而不是放在 app.MapGet 方法上。
app.MapGet("/extension-methods", () => "Hello world!")
.WithSummary("This is a summary.")
.WithDescription("This is a description.");
app.MapGet("/attributes",
[EndpointSummary("This is a summary.")]
[EndpointDescription("This is a description.")]
() => "Hello world!");
下列範例示範如何設定摘要和描述。
[EndpointSummary("This is a summary.")]
[EndpointDescription("This is a description.")]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
OpenAPI 支援將每個端點上的標籤指定為分類形式。
在最小 API 中,標籤可以透過[Tags]屬性或WithTags擴充方法來設定。
下列範例示範設定標記的不同策略。
app.MapGet("/extension-methods", () => "Hello world!")
.WithTags("todos", "projects");
app.MapGet("/attributes",
[Tags("todos", "projects")]
() => "Hello world!");
在控制器型應用程式中,控制器名稱會自動新增為其每個端點上的標記,但可以使用 [Tags] 屬性來覆寫該標記。
下列範例示範如何設定標記。
[Tags(["todos", "projects"])]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
operationId
OpenAPI 支援每個端點上的 operationId 作為作業的唯一識別碼或名稱。
在 Minimal API 中,操作 ID 可以透過[EndpointName]屬性或WithName擴充方法來設定。
下列範例示範設定 operationId 的不同策略。
app.MapGet("/extension-methods", () => "Hello world!")
.WithName("FromExtensionMethods");
app.MapGet("/attributes",
[EndpointName("FromAttributes")]
() => "Hello world!");
在控制器型應用程式中,可以使用 [EndpointName] 屬性來設定 operationId。
下列範例示範如何設定 operationId。
[EndpointName("FromAttributes")]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
parameters
OpenAPI 支援 API 所使用的標註路徑、查詢字串、標頭和 cookie 參數。
架構會根據路由處理常式的簽章,自動推斷要求參數的型別。
[Description] 屬性可用來提供參數的描述。
[HttpGet("attributes")]
public IResult Attributes(
[Description("This is a description.")] string name)
return Results.Ok("Hello world!");
描述請求主體
OpenAPI 中的 requestBody 欄位描述了 API 用戶端可傳送給伺服器的請求內容,包括支援的內容類型及內容結構。
當端點處理方法接受從請求主體綁定的參數時,ASP.NET Core 會為 OpenAPI 文件中的操作產生對應的 requestBody。 您也可以使用屬性或擴充方法來指定要求主體的元數據。 可以使用 文件轉換器 或 作業轉換器來設定其他中繼資料。
如果端點沒有定義任何綁定到請求主體的參數,而是直接從 HttpContext 取用請求主體,ASP.NET Core 就會提供機制來指定請求主體的元資料。 處理請求主體為資料流的端點常見案例是這樣的。
某些請求正文的元數據可以由路由處理器方法中的FromBody或FromForm參數來確定。
您可以在參數的[Description]屬性上,使用FromBody或FromForm來設定請求本文的描述。
如果FromBody參數不可為 Null,且EmptyBodyBehavior在Allow屬性中未設定為FromBody,則要求的本文是必需的,且在產生的 OpenAPI 文件中,required的requestBody欄位會設定為true。
表單內容始終是必需的,並且已將 required 設定為 true。
使用 文件轉換器 或 作業轉換器 來設定 example、 examples或 encoding 欄位,或在產生的 OpenAPI 文件中新增要求內文的規格延伸。
設定要求本文元數據的其他機制取決於所開發的應用程式類型,如下幾節所述。
所產生的 OpenAPI 文件中,請求主體的內容類型是由綁定到請求主體的參數類型或使用 Accepts 擴充方法指定的參數類型決定的。
預設情況下,FromBody 參數的內容類型為 application/json,而 FromForm 參數的內容類型為 multipart/form-data 或 application/x-www-form-urlencoded。
這些預設內容類型的支援內建於基本 API 中,而其他內容類型可以使用自定義系結來處理。
如需詳細資訊,請參閱最小 API 文件的 自訂繫結 主題。
可以指定請求主體的內容類型的幾種不同方法。
如果 FromBody 參數的類型實作了 IEndpointParameterMetadataProvider,ASP.NET Core 會使用此介面來決定請求主體中的內容類型。
框架利用 PopulateMetadata 此介面的方法來設定請求內容類型以及請求正文內容的類型。 例如,接收Todo 或 application/xml 內容類型的text/xml 類別,可使用IEndpointParameterMetadataProvider 將此資訊提供給架構。
public class Todo : IEndpointParameterMetadataProvider
public static void PopulateMetadata(
ParameterInfo parameter,
EndpointBuilder builder)
builder.Metadata.Add(
new AcceptsMetadata(
["application/xml", "text/xml"],
typeof(Todo)
Accepts 擴充方法也可以用來指定請求正文的內容類型。
在下列範例中,端點會在請求主體中接受 Todo 物件,並且期待內容型別為 application/xml。
app.MapPut("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
由於 application/xml 不是內建內容類型,因此 類別 Todo 必須實 IBindableFromHttpContext<TSelf> 作 介面,以提供要求主體的自定義系結。 例如:
public class Todo : IBindableFromHttpContext<Todo>
public static async ValueTask<Todo?> BindAsync(
HttpContext context,
ParameterInfo parameter)
var xmlDoc = await XDocument.LoadAsync(context.Request.Body, LoadOptions.None, context.RequestAborted);
var serializer = new XmlSerializer(typeof(Todo));
return (Todo?)serializer.Deserialize(xmlDoc.CreateReader());
如果端點未定義系結至要求本文的任何參數,請使用 Accepts 擴充方法指定端點接受的內容類型。
如果您指定 Accepts 多次,則只會使用最後一個的元數據-- 它們不會合併。
在基於控制器的應用程式中,產生的 OpenAPI 文件中請求主體的內容類型,是根據綁定於請求主體的參數類型、 InputFormatter 應用程式中設定的型別,或路由 [Consumes] 處理方法中的屬性來決定。
ASP.NET Core 使用 InputFormatter 來反序列化 FromBody 請求主體。
InputFormatters 是在傳遞至應用程式服務集合的MvcOptions擴充方法中AddControllers所設定的。
每個輸入格式化器在其屬性中 SupportedMediaTypes 宣告可處理的內容類型,以及可處理的正體內容類型,並使用其 CanReadType 方法。
ASP.NET Core MVC 內建 JSON 和 XML 的輸入格式化器,但預設僅啟用 JSON 輸入格式化器。
內建的 JSON 輸入格式器支援 application/json、 text/json和 application/*+json 內容類型,而內建的 XML 輸入格式器則支援 application/xml、 text/xml和 application/*+xml 內容類型。
根據預設,FromBody要求本文的內容類型可以是任何InputFormatter參數型別由FromBody接受的內容類型。 對於帶有 FromForm 參數的請求體,預設內容類型為 multipart/form-data 或 application/x-www-form-urlencoded。 這些內容類型會包含在生成的 OpenAPI 文件中,若在路由處理方法中未指定 [Consumes] 屬性。
路由處理程序接受的內容類型可以透過端點的 過濾器 (動作範圍)來限制。
屬性 [Consumes] 會將動作範圍篩選新增至端點,以限制路由處理程式將接受的內容類型。
此時,生成的 OpenAPI 文件中的 requestBody 只會包含屬性中 [Consumes] 指定的內容類型。
屬性 [Consumes] 無法新增對沒有相關聯輸入格式子之內容類型的支援,而產生的OpenAPI檔不包含任何沒有相關聯輸入格式子的內容類型。
針對 JSON 或 XML 以外的內容類型,您必須建立自訂輸入格式器。
欲了解更多資訊與範例,請參閱 ASP.NET Core Web API 中的 自訂格式化器。
如果路由處理程式沒有 FromBody 或 FromForm 參數,路由處理程式可能會直接從 Request.Body 數據流讀取要求本文,而且可能會使用 [Consumes] 屬性來限制允許的內容類型,但 OpenAPI 檔中不會產生任何 requestBody。
描述回應類型
OpenAPI 支援提供從 API 傳回的回應描述。 ASP.NET Core 提供多種策略來設定端點的回應元資料。 可設定的回應元資料包括狀態碼、回應主體的類型,以及回應的內容類型。 OpenAPI 中的回應可能會有其他元數據,例如描述、標頭、連結和範例。 可以使用 文件轉換器 或 作業轉換器來設定此額外的中繼資料。
設定回應元數據的特定機制取決於正在開發的應用程式類型。
Produces擴充方法可在端點上指定狀態碼、回應體型態及端點回應的內容類型。
[ProducesResponseType]或 ProducesResponseTypeAttribute<T> 屬性可用來指定響應主體的類型。
路由處理器可用來回傳一個型別,該型別實作 IEndpointMetadataProvider 以指定回應體的型別與內容型別。
ProducesProblem端點上的擴充方法可用來指定錯誤回應的狀態碼與內容類型。
請注意,Produces 和 ProducesProblem 擴充方法於 RouteHandlerBuilder 和 RouteGroupBuilder 都受支援。 例如,這允許針對群組中的所有作業定義一組常見的錯誤回應。
未由上述其中一個策略指定時,:
回應的狀態代碼預設為 200。
回應主體的架構可以從端點方法的隱含或明確傳回類型推斷,例如,從 T 中 Task<TResult>推斷,否則會被視為未指定。
指定或推斷之響應主體的內容類型為 「application/json」。。
在「Minimal API」中,Produces 擴充方法和 [ProducesResponseType] 屬性只會設定端點的回應中繼資料。 它們不會修改或限制端點的行為,其可能會傳回與元數據指定的狀態代碼或響應主體類型不同的狀態代碼或響應主體類型,而且內容類型是由路由處理程式方法的傳回類型所決定,而不論屬性或擴充方法中指定的任何內容類型為何。
擴充 Produces 方法可以指定端點的回應類型,其預設狀態代碼為 200,預設內容類型為 application/json。 下面這個範例可說明這點:
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
[ProducesResponseType]可用來將回應元數據新增至端點。 請注意,屬性是套用在路由處理方法上,而不是應用在建立路由的方法調用上,如下列範例所示:
app.MapGet("/todos",
[ProducesResponseType<List<Todo>>(200)]
async (TodoDb db) => await db.Todos.ToListAsync());
[ProducesResponseType]、 [Produces]和 [ProducesDefaultResponseType] 也支援稱為 的選擇性字串屬性 Description ,可用來描述回應。 這適用於說明客戶端預期特定回應的原因或時機:
app.MapGet("/todos/{id}",
[ProducesResponseType<Todo>(200,
Description = "Returns the requested Todo item.")]
[ProducesResponseType(404, Description = "Requested item not found.")]
[ProducesDefault(Description = "Undocumented status code.")]
async (int id, TodoDb db) => /* Code here */);
在實現端點路由處理器時使用 TypedResults,會自動包含端點回應類型的中繼資料。 例如,下列程式碼會自動以具有 200 內容型別的 application/json 狀態碼的回應來註釋端點。
app.MapGet("/todos", async (TodoDb db) =>
var todos = await db.Todos.ToListAsync();
return TypedResults.Ok(todos);
只有那些實作 IEndpointMetadataProvider 的傳回型別會在 OpenAPI 文件中建立一個 responses 條目。 以下是產生TypedResults項目之responses一些輔助方法的部分清單:
所有這些方法,除了 NoContent 之外,都有一個可指定響應主體類型的泛型多載。
您可以實作 類別來設定端點元數據,並從路由處理程式傳回它。
設定 ProblemDetails 的回應
為可能傳回 ProblemDetails 回應的端點設定回應類型時,可以使用下列專案來新增端點的適當回應元數據:
ProducesProblem
ProducesValidationProblem 擴充方法。
TypedResults 的狀態代碼在(400-499)範圍內。
欲了解更多如何配置最小 API 應用程式以回傳 ProblemDetails 回應的資訊,請參見 Handle errors in ASP.NET Core APIs。
多個回應型別
如果端點可以在不同案例中傳回不同的回應型別,您可以透過下列方式提供中繼資料:
多次調用 Produces 擴充方法,如下列範例所示:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
在簽章中使用 Results<TResult1,TResult2,TResult3,TResult4,TResult5,TResult6>,處理常式主體中使用 TypedResults,如下列範例所示:
app.MapGet("/book/{id}", Results<Ok<Book>, NotFound>
(int id, List<Book> bookList) =>
return bookList.FirstOrDefault((i) => i.Id == id) is Book book
? TypedResults.Ok(book)
: TypedResults.NotFound();
Results<TResult1,TResult2,TResultN>
聯合類型聲明路由處理程序會返回多個實作IResult的具體類型,其中任何實作IEndpointMetadataProvider的類型都將為端點的中繼資料做出貢獻。
聯合型別會實作隱含轉換運算子。 這些運算子可讓編譯器自動將泛型引數中指定的型別轉換為聯合型別的實例。 此功能的額外優點是提供編譯時檢查,以確保路由處理常式僅傳回它宣告的結果。 嘗試傳回未宣告為其中一個泛型引數的型別至 Results<TResult1,TResult2,TResultN> 會產生編譯錯誤。
在基於控制器的應用程式中,ASP.NET Core 可以從動作方法簽名、屬性和慣例中擷取回應元資料。
你可以使用 [ProducesResponseType] or ProducesResponseTypeAttribute<T> 屬性來指定狀態碼、回應主體的類型,以及動作方法回應的內容類型。
您可以使用 [Produces] 或 ProducesAttribute<T> 屬性來指定回應主體的類型。
您可以使用 [ProducesDefaultResponseType] 屬性來指定「預設」回應的響應主體類型。
您可以使用 [ProducesErrorResponseType] 屬性來指定錯誤回應的響應主體類型。 不過請注意,這只是補充由屬性指定的 [ProducesResponseType] 狀態碼和內容類型,而該屬性為 4XX 狀態碼。
只有一或 [Produces] 個屬性 ProducesAttribute<T> 可以套用至動作方法,但具有不同狀態代碼的多個 [ProducesResponseType] 或 ProducesResponseTypeAttribute<T> 屬性可以套用至單一動作方法。
上述所有屬性都可以套用至個別動作方法,或套用至控制器中所有動作方法的控制器類別。
[ProducesResponseType]、 [Produces]和 [ProducesDefaultResponseType] 也支援稱為 的選擇性字串屬性 Description ,可用來描述回應。 這適用於說明客戶端預期特定回應的原因或時機:
[HttpGet("/todos/{id}")]
[ProducesResponseType<Todo>(StatusCodes.Status200OK,
"application/json", Description = "Returns the requested Todo item.")]
[ProducesResponseType(StatusCodes.Status404NotFound,
Description = "Requested Todo item not found.")]
[ProducesDefault(Description = "Undocumented status code.")]
public async Task<ActionResult<Todo>> GetTodoItem(string id, Todo todo)
當屬性未指定時:
回應的狀態代碼預設為 200。
2xx 回應的響應正文架構可以從動作方法的返回類型推斷,例如從 T 中的 ActionResult<TValue> 推斷,但在其他情況下則視為未指定。
4xx 回應的回應主體架構被推斷為問題詳細資訊物件。
3xx 和 5xx 回應的響應主體架構被視為未指定。
回應本文的內容類型可以從動作方法的傳回型別和輸出格式器集合推斷。
根據預設,不會進行編譯時間檢查,以確保以 [ProducesResponseType] 屬性 指定的響應元數據與動作方法的實際行為一致,此方法可能會傳回與元數據指定的不同狀態代碼或回應主體類型。 若要啟用這些檢查, 請啟用 Web API 分析器。
在控制器式應用程式中,當模型驗證失敗或動作方法回傳 4xx 或 5xx HTTP 狀態碼時,ASP.NET 會以 ProblemDetails 回應類型。 驗證錯誤通常會使用 400 狀態代碼,因此您可以使用 [ProducesResponseType] 屬性 來指定動作的錯誤回應,如下列範例所示:
[HttpPut("/todos/{id}")]
[ProducesResponseType<Todo>(StatusCodes.Status200OK,
"application/json")]
[ProducesResponseType<Todo>(StatusCodes.Status201Created,
"application/json")]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest,
"application/problem+json")]
public async Task<ActionResult<Todo>> CreateOrReplaceTodo(string id, Todo todo)
此範例也會說明如何定義動作方法的多個回應類型,包括響應主體的內容類型。
從生成的文件中排除端點
根據預設,應用程式中定義的所有端點都會記錄在產生的 OpenAPI 檔案中,但可以使用屬性或擴充方法從檔中排除端點。
指定應排除之端點的機制取決於所開發的應用程式類型。
下列範例示範從產生的 OpenAPI 文件中排除指定端點的不同策略。
app.MapGet("/extension-method", () => "Hello world!")
.ExcludeFromDescription();
app.MapGet("/attributes",
[ExcludeFromDescription]
() => "Hello world!");
在控制器型應用程式中, [ApiExplorerSettings] 屬性可用來從 OpenAPI 檔中排除控制器類別中的端點或所有端點。
下列範例示範如何從產生的 OpenAPI 檔中排除端點:
[HttpGet("/private")]
[ApiExplorerSettings(IgnoreApi = true)]
public IActionResult PrivateEndpoint() {
return Ok("This is a private endpoint");
要求或回應主體中使用的 C# 類別或記錄會以所產生 OpenAPI 文件的結構描表示。
預設情況下,架構中只 public 表示屬性,但也可 JsonSerializerOptions 為欄位建立結構屬性。
當 PropertyNamingPolicy 設定為駝峰箱(這是 ASP.NET 網頁應用程式的預設值),結構中的屬性名稱即為類別或記錄屬性名稱的駝峰箱形式。
[JsonPropertyName] 可用於個別屬性,以指定結構描述中的屬性名稱。
JSON 架構庫會將標準 C# 數值類型對應至 OpenAPItype 和format,根據應用程式中使用的NumberHandlingJsonSerializerOptions屬性。 在 ASP.NET Core Web API 應用程式中,此屬性的預設值為 JsonNumberHandling.AllowReadingFromString。
NumberHandling當 屬性設定為 JsonNumberHandling.AllowReadingFromString時,數值類型會對應如下:
C# 類型
開放API type
開放API format
請注意,在控制器型應用程式中,這些屬性會將篩選新增至作業,以驗證任何傳入的資料是否符合條件約束。 在最小 API 中,這些屬性會在產生的結構描述中設定中繼資料,但必須透過端點篩選、路由處理常式邏輯或透過第三方套件明確執行驗證。
屬性也可以放在記錄定義的參數清單中,但必須包含 property 修飾詞。 例如:
public record Todo(
[property: Required]
[property: Description("The unique identifier for the todo")]
int Id,
[property: Description("The title of the todo")]
[property: MaxLength(120)]
string Title,
[property: Description("Whether the todo has been completed")]
bool Completed
required
在類別、結構或記錄中,具有 [Required] 屬性或 必要 修飾詞的屬性一律位於 required 對應的結構描述中。
您也可以根據類別、結構或記錄的建構函式(隱含和明確)來要求其他屬性。
對於具有單一公用建構函式的類別或記錄類別,在對應的架構中,任何作為建構函式參數且名稱和類型相同的屬性(不區分大小寫比對)都是必需的。
對於具有多個公用建構函式的類別或記錄類別,不需要其他屬性。
對於結構或記錄結構,不需要其他屬性,因為 C# 一律會定義結構的隱含無參數建構函式。
C# 中的列舉類型是以整數為基礎,但可以使用 JSON 中的 [JsonConverter] 和 JsonStringEnumConverter 表示為字串。 當列舉類型在 JSON 中以字串表示時,產生的結構描述將具有列舉字串值的 enum 屬性。
下列範例示範如何使用 JsonStringEnumConverter 來將列舉表示為 JSON 中的字串:
[JsonConverter(typeof(JsonStringEnumConverter<DayOfTheWeekAsString>))]
public enum DayOfTheWeekAsString
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
特殊案例是當列舉類型具有 [Flags] 屬性時,表示列舉可以視為位字段,也就是一組旗標。 具有enum的旗標[JsonConverterAttribute]在生成的架構中被定義為type: string,且沒有enum屬性。 不會產生 enum 任何屬性,因為值可以是列舉值的任何組合。 例如,下列enum可能會有"Pepperoni, Sausage"或"Sausage, Mushrooms, Anchovies"之類的值:
[Flags, JsonConverter(typeof(JsonStringEnumConverter<PizzaToppings>))]
public enum PizzaToppings {
Pepperoni = 1,
Sausage = 2,
Mushrooms = 4,
Anchovies = 8
不含 [JsonConverter] 的列舉類型會在產生的結構描述中定義為 type: integer。
注意:[AllowedValues] 屬性不會設定某個屬性的 enum 值。
全域設定 JSON 選項 會顯示如何全域設定 JsonStringEnumConverter 。
可為 Null
定義為可為 Null 值或參考型別的屬性會在產生的架構中顯示,並使用關鍵字 type,其值為包含 null 作為其中一種型別的陣列。 這與 System.Text.Json 反序列化器的預設行為一致,它接受 null 作為可為 NULL 的屬性的有效值。
例如,定義為 string? 的 C# 屬性會在產生的架構中表示為:
"nullableString": {
"description": "A property defined as string?",
"type": [
"null",
"string"
如果應用程式設定為產生 OpenAPI v3.0 或 OpenAPI v2 檔,則產生的架構中有可為 Null 的值或參考類型 nullable: true ,因為這些 OpenAPI 版本不允許 type 字段成為陣列。
additionalProperties
結構定義預設不會產生 additionalProperties 判斷提示,這表示 true 的預設值。 這與 System.Text.Json 還原序列化程式的預設行為一致,它會默默忽略 JSON 物件中的其他屬性。
如果結構描述的其他屬性應該只有特定類型的值,請將屬性或類別定義為 Dictionary<string, type>。 字典的索引鍵類型必須是 string。 這會產生結構描述,其中 additionalProperties 指定 "type" 的結構描述為必要的實值類型。
使用父類別上的 [JsonPolymorphic] 和 [JsonDerivedType] 屬性來指定多型類型的歧視性字段和子類型。
[JsonDerivedType] 將鑑別子欄位新增到每個子類別的結構模式中,並通過列舉來指定每個子類別的特定鑑別子值。 這個屬性也會修改每個衍生類別的建構函式,以設定鑑別子值。
具有 [JsonPolymorphic] 屬性的抽象類別具有 discriminator 結構描述中的欄位,但具有 [JsonPolymorphic] 屬性的實體類別沒有 discriminator 欄位。 OpenAPI 要求鑑別子屬性是結構描述中的必要屬性,但由於實體基底類別中未定義鑑別子屬性,所以結構描述不能包含 discriminator 欄位。
結構描述轉換器可用來覆寫任何預設的中繼資料,或在生成的結構描述中新增其他中繼資料,例如 example 值。 如需詳細資訊,請參閱使用結構描述轉換器。
全域設定 JSON 串行化選項
下列程式代碼會全域設定一些 JSON 選項,適用於基本 API 和控制器型 API:
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http.Json;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.Configure<JsonOptions>(options =>
options.SerializerOptions.Converters.Add(
new JsonStringEnumConverter<DayOfTheWeekAsString>());
options.SerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
options.SerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.CamelCase;
builder.Services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(
new JsonStringEnumConverter<DayOfTheWeekAsString>());
options.JsonSerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.CamelCase;
var app = builder.Build();
if (app.Environment.IsDevelopment())
app.MapOpenApi();
app.UseHttpsRedirection();
app.MapGet("/", () =>
var day = DayOfTheWeekAsString.Friday;
return Results.Json(day);
app.MapPost("/", (DayOfTheWeekAsString day) =>
return Results.Json($"Received: {day}");
app.UseRouting();
app.MapControllers();
app.Run();
MVC JSON 選項和全域 JSON 選項
下表顯示MVC JSON 選項和全域最小 API JSON 選項之間的主要差異:
ASP.NET 從網頁應用程式的端點收集元資料,並用來產生 OpenAPI 文件。
在控制器型應用程式中,當控制器具有[EndpointDescription]時,會從[HttpPost]、[Produces]和[ApiController]等屬性中收集元數據。
在最小 API 中,元資料可從屬性收集,但也可透過擴充方法及其他策略(如從路由處理器回傳 TypedResults )設定。
下表提供所收集中繼資料的概覽,並說明設定中繼資料的策略。
Metadata
Attribute
下列範例示範設定摘要和描述的不同策略。
請注意,屬性置放在委派方法上,而不是放在 app.MapGet 方法上。
app.MapGet("/extension-methods", () => "Hello world!")
.WithSummary("This is a summary.")
.WithDescription("This is a description.");
app.MapGet("/attributes",
[EndpointSummary("This is a summary.")]
[EndpointDescription("This is a description.")]
() => "Hello world!");
下列範例示範如何設定摘要和描述。
[EndpointSummary("This is a summary.")]
[EndpointDescription("This is a description.")]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
OpenAPI 支援將每個端點上的標籤指定為分類形式。
在最小 API 中,標籤可以透過[Tags]屬性或WithTags擴充方法來設定。
下列範例示範設定標記的不同策略。
app.MapGet("/extension-methods", () => "Hello world!")
.WithTags("todos", "projects");
app.MapGet("/attributes",
[Tags("todos", "projects")]
() => "Hello world!");
在控制器型應用程式中,控制器名稱會自動新增為其每個端點上的標記,但可以使用 [Tags] 屬性來覆寫該標記。
下列範例示範如何設定標記。
[Tags(["todos", "projects"])]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
operationId
OpenAPI 支援每個端點上的 operationId 作為作業的唯一識別碼或名稱。
在 Minimal API 中,操作 ID 可以透過[EndpointName]屬性或WithName擴充方法來設定。
下列範例示範設定 operationId 的不同策略。
app.MapGet("/extension-methods", () => "Hello world!")
.WithName("FromExtensionMethods");
app.MapGet("/attributes",
[EndpointName("FromAttributes")]
() => "Hello world!");
在控制器型應用程式中,可以使用 [EndpointName] 屬性來設定 operationId。
下列範例示範如何設定 operationId。
[EndpointName("FromAttributes")]
[HttpGet("attributes")]
public IResult Attributes()
return Results.Ok("Hello world!");
parameters
OpenAPI 支援 API 所使用的標註路徑、查詢字串、標頭和 cookie 參數。
架構會根據路由處理常式的簽章,自動推斷要求參數的型別。
[Description] 屬性可用來提供參數的描述。
下列範例示範如何設定參數的描述。
[HttpGet("attributes")]
public IResult Attributes([Description("This is a description.")] string name)
return Results.Ok("Hello world!");
描述請求主體
OpenAPI 中的 requestBody 欄位描述了 API 用戶端可傳送給伺服器的請求內容,包括支援的內容類型及內容結構。
當端點處理方法接受從請求主體綁定的參數時,ASP.NET Core 會為 OpenAPI 文件中的操作產生對應的 requestBody。 您也可以使用屬性或擴充方法來指定要求主體的元數據。 可以使用 文件轉換器 或 作業轉換器來設定其他中繼資料。
如果端點沒有定義任何綁定到請求主體的參數,而是直接從 HttpContext 取用請求主體,ASP.NET Core 就會提供機制來指定請求主體的元資料。 處理請求主體為資料流的端點常見案例是這樣的。
某些請求正文的元數據可以由路由處理器方法中的FromBody或FromForm參數來確定。
您可以在參數的[Description]屬性上,使用FromBody或FromForm來設定請求本文的描述。
如果FromBody參數不可為 Null,且EmptyBodyBehavior在Allow屬性中未設定為FromBody,則要求的本文是必需的,且在產生的 OpenAPI 文件中,required的requestBody欄位會設定為true。
表單內容始終是必需的,並且已將 required 設定為 true。
使用 文件轉換器 或 作業轉換器 來設定 example、 examples或 encoding 欄位,或在產生的 OpenAPI 文件中新增要求內文的規格延伸。
設定要求本文元數據的其他機制取決於所開發的應用程式類型,如下幾節所述。
所產生的 OpenAPI 文件中,請求主體的內容類型是由綁定到請求主體的參數類型或使用 Accepts 擴充方法指定的參數類型決定的。
預設情況下,FromBody 參數的內容類型為 application/json,而 FromForm 參數的內容類型為 multipart/form-data 或 application/x-www-form-urlencoded。
這些預設內容類型的支援內建於基本 API 中,而其他內容類型可以使用自定義系結來處理。
如需詳細資訊,請參閱最小 API 文件的 自訂繫結 主題。
可以指定請求主體的內容類型的幾種不同方法。
如果 FromBody 參數的類型實作了 IEndpointParameterMetadataProvider,ASP.NET Core 會使用此介面來決定請求主體中的內容類型。
框架利用 PopulateMetadata 此介面的方法來設定請求內容類型以及請求正文內容的類型。 例如,接收Todo 或 application/xml 內容類型的text/xml 類別,可使用IEndpointParameterMetadataProvider 將此資訊提供給架構。
public class Todo : IEndpointParameterMetadataProvider
public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
builder.Metadata.Add(new AcceptsMetadata(["application/xml", "text/xml"], typeof(Todo)));
Accepts 擴充方法也可以用來指定請求正文的內容類型。
在下列範例中,端點會在請求主體中接受 Todo 物件,並且期待內容型別為 application/xml。
app.MapPut("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
由於 application/xml 不是內建內容類型,因此 類別 Todo 必須實 IBindableFromHttpContext<TSelf> 作 介面,以提供要求主體的自定義系結。 例如:
public class Todo : IBindableFromHttpContext<Todo>
public static async ValueTask<Todo?> BindAsync(HttpContext context, ParameterInfo parameter)
var xmlDoc = await XDocument.LoadAsync(context.Request.Body, LoadOptions.None, context.RequestAborted);
var serializer = new XmlSerializer(typeof(Todo));
return (Todo?)serializer.Deserialize(xmlDoc.CreateReader());
如果端點未定義系結至要求本文的任何參數,請使用 Accepts 擴充方法指定端點接受的內容類型。
如果您指定 <AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.Accepts%2A> 多次,則只會使用最後一個來源的元數據 -- 它們不會合併。
在基於控制器的應用程式中,產生的 OpenAPI 文件中請求主體的內容類型,是根據綁定於請求主體的參數類型、 InputFormatter 應用程式中設定的型別,或路由 [Consumes] 處理方法中的屬性來決定。
ASP.NET Core 使用 InputFormatter 來反序列化 FromBody 請求主體。
InputFormatters 是在傳遞至應用程式服務集合的MvcOptions擴充方法中AddControllers所設定的。
每個輸入格式化器在其屬性中 SupportedMediaTypes 宣告可處理的內容類型,以及可處理的正體內容類型,並使用其 CanReadType 方法。
ASP.NET Core MVC 內建 JSON 和 XML 的輸入格式化器,但預設僅啟用 JSON 輸入格式化器。
內建的 JSON 輸入格式器支援 application/json、 text/json和 application/*+json 內容類型,而內建的 XML 輸入格式器則支援 application/xml、 text/xml和 application/*+xml 內容類型。
根據預設,FromBody要求本文的內容類型可以是任何InputFormatter參數型別由FromBody接受的內容類型。 對於帶有 FromForm 參數的請求體,預設內容類型為 multipart/form-data 或 application/x-www-form-urlencoded。若路由處理方法未指定屬性, [Consumes] 這些內容類型會包含在生成的 OpenAPI 文件中。
路由處理程序接受的內容類型可以透過端點的 過濾器 (動作範圍)來限制。
屬性 [Consumes] 會將動作範圍篩選新增至端點,以限制路由處理程式將接受的內容類型。
此時,生成的 OpenAPI 文件中的 requestBody 只會包含屬性中 [Consumes] 指定的內容類型。
屬性 [Consumes] 無法新增對沒有相關聯輸入格式子之內容類型的支援,而產生的OpenAPI檔不包含任何沒有相關聯輸入格式子的內容類型。
針對 JSON 或 XML 以外的內容類型,您必須建立自訂輸入格式器。
欲了解更多資訊與範例,請參閱 ASP.NET Core Web API 中的 自訂格式化器。
如果路由處理程式沒有 FromBody 或 FromForm 參數,路由處理程式可能會直接從 Request.Body 數據流讀取要求本文,而且可能會使用 [Consumes] 屬性來限制允許的內容類型,但 OpenAPI 檔中不會產生任何 requestBody。
描述回應類型
OpenAPI 支援提供從 API 傳回的回應描述。 ASP.NET Core 提供多種策略來設定端點的回應元資料。 可設定的回應元資料包括狀態碼、回應主體的類型,以及回應的內容類型。 OpenAPI 中的回應可能會有其他元數據,例如描述、標頭、連結和範例。 可以使用 文件轉換器 或 作業轉換器來設定此額外的中繼資料。
設定回應元數據的特定機制取決於正在開發的應用程式類型。
Produces擴充方法可在端點上指定狀態碼、回應體型態及端點回應的內容類型。
[ProducesResponseType]或 ProducesResponseTypeAttribute<T> 屬性可用來指定響應主體的類型。
路由處理器可用來回傳一個型別,該型別實作 IEndpointMetadataProvider 以指定回應體的型別與內容型別。
ProducesProblem端點上的擴充方法可用來指定錯誤回應的狀態碼與內容類型。
請注意,Produces 和 ProducesProblem 擴充方法於 RouteHandlerBuilder 和 RouteGroupBuilder 都受支援。 例如,這允許針對群組中的所有作業定義一組常見的錯誤回應。
未由上述其中一個策略指定時,:
回應的狀態代碼預設為 200。
回應主體的架構可以從端點方法的隱含或明確傳回類型推斷,例如,從 T 中 Task<TResult>推斷,否則會被視為未指定。
指定或推斷之響應主體的內容類型為 「application/json」。。
在「Minimal API」中,Produces 擴充方法和 [ProducesResponseType] 屬性只會設定端點的回應中繼資料。 它們不會修改或限制端點的行為,其可能會傳回與元數據指定的狀態代碼或響應主體類型不同的狀態代碼或響應主體類型,而且內容類型是由路由處理程式方法的傳回類型所決定,而不論屬性或擴充方法中指定的任何內容類型為何。
擴充 Produces 方法可以指定端點的回應類型,其預設狀態代碼為 200,預設內容類型為 application/json。 下面這個範例可說明這點:
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
[ProducesResponseType]可用來將回應元數據新增至端點。 請注意,屬性是套用在路由處理方法上,而不是應用在建立路由的方法調用上,如下列範例所示:
app.MapGet("/todos",
[ProducesResponseType<List<Todo>>(200)]
async (TodoDb db) => await db.Todos.ToListAsync());
在實現端點路由處理器時使用 TypedResults,會自動包含端點回應類型的中繼資料。 例如,下列程式碼會自動以具有 200 內容型別的 application/json 狀態碼的回應來註釋端點。
app.MapGet("/todos", async (TodoDb db) =>
var todos = await db.Todos.ToListAsync();
return TypedResults.Ok(todos);
只有那些實作 IEndpointMetadataProvider 的傳回型別會在 OpenAPI 文件中建立一個 responses 條目。 以下是產生TypedResults項目之responses一些輔助方法的部分清單:
所有這些方法,除了 NoContent 之外,都有一個可指定響應主體類型的泛型多載。
您可以實作 類別來設定端點元數據,並從路由處理程式傳回它。
設定 ProblemDetails 的回應
為可能傳回 ProblemDetails 回應的端點設定回應類型時,可以使用下列專案來新增端點的適當回應元數據:
ProducesProblem
ProducesValidationProblem 擴充方法。
TypedResults 的狀態代碼在(400-499)範圍內。
欲了解更多如何配置最小 API 應用程式以回傳 ProblemDetails 回應的資訊,請參見 Handle errors in ASP.NET Core APIs。
多個回應型別
如果端點可以在不同案例中傳回不同的回應型別,您可以透過下列方式提供中繼資料:
多次調用 Produces 擴充方法,如下列範例所示:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
在簽章中使用 Results<TResult1,TResult2,TResult3,TResult4,TResult5,TResult6>,處理常式主體中使用 TypedResults,如下列範例所示:
app.MapGet("/book/{id}", Results<Ok<Book>, NotFound>
(int id, List<Book> bookList) =>
return bookList.FirstOrDefault((i) => i.Id == id) is Book book
? TypedResults.Ok(book)
: TypedResults.NotFound();
Results<TResult1,TResult2,TResultN>
聯合類型聲明路由處理程序會返回多個實作IResult的具體類型,其中任何實作IEndpointMetadataProvider的類型都將為端點的中繼資料做出貢獻。
聯合型別會實作隱含轉換運算子。 這些運算子可讓編譯器自動將泛型引數中指定的型別轉換為聯合型別的實例。 此功能的額外優點是提供編譯時檢查,以確保路由處理常式僅傳回它宣告的結果。 嘗試傳回未宣告為其中一個泛型引數的型別至 Results<TResult1,TResult2,TResultN> 會產生編譯錯誤。
在基於控制器的應用程式中,ASP.NET Core 可以從動作方法簽名、屬性和慣例中擷取回應元資料。
你可以使用 [ProducesResponseType] or ProducesResponseTypeAttribute<T> 屬性來指定狀態碼、回應主體的類型,以及動作方法回應的內容類型。
您可以使用 [Produces] 或 ProducesAttribute<T> 屬性來指定回應主體的類型。
您可以使用 [ProducesDefaultResponseType] 屬性來指定「預設」回應的響應主體類型。
您可以使用 [ProducesErrorResponseType] 屬性來指定錯誤回應的響應主體類型。 不過請注意,這只是補充屬性中 4XX 狀態碼所指定的 [ProducesResponseType] 狀態碼和內容類型。
只有一或 [Produces] 個屬性 ProducesAttribute<T> 可以套用至動作方法,但具有不同狀態代碼的多個 [ProducesResponseType] 或 ProducesResponseTypeAttribute<T> 屬性可以套用至單一動作方法。
上述所有屬性都可以套用至個別動作方法,或套用至控制器中所有動作方法的控制器類別。
當屬性未指定時:
回應的狀態代碼預設為 200。
2xx 回應的響應正文架構可以從動作方法的返回類型推斷,例如從 T 中的 ActionResult<TValue> 推斷,但在其他情況下則視為未指定。
4xx 回應的回應主體架構被推斷為問題詳細資訊物件。
3xx 和 5xx 回應的響應主體架構被視為未指定。
回應本文的內容類型可以從動作方法的傳回型別和輸出格式器集合推斷。
根據預設,不會進行編譯時間檢查,以確保以 [ProducesResponseType] 屬性 指定的響應元數據與動作方法的實際行為一致,此方法可能會傳回與元數據指定的不同狀態代碼或回應主體類型。 若要啟用這些檢查, 請啟用 Web API 分析器。
在控制器式應用程式中,當模型驗證失敗或動作方法回傳 4xx 或 5xx HTTP 狀態碼時,ASP.NET 會以 ProblemDetails 回應類型。 驗證錯誤通常會使用 400 狀態代碼,因此您可以使用 [ProducesResponseType] 屬性 來指定動作的錯誤回應,如下列範例所示:
[HttpPut("/todos/{id}")]
[ProducesResponseType<Todo>(StatusCodes.Status200OK, "application/json")]
[ProducesResponseType<Todo>(StatusCodes.Status201Created, "application/json")]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest, "application/problem+json")]
public async Task<ActionResult<Todo>> CreateOrReplaceTodo(string id, Todo todo)
此範例也會說明如何定義動作方法的多個回應類型,包括響應主體的內容類型。
從生成的文件中排除端點
根據預設,應用程式中定義的所有端點都會記錄在產生的 OpenAPI 檔案中,但可以使用屬性或擴充方法從檔中排除端點。
指定應排除之端點的機制取決於所開發的應用程式類型。
下列範例示範從產生的 OpenAPI 文件中排除指定端點的不同策略。
app.MapGet("/extension-method", () => "Hello world!")
.ExcludeFromDescription();
app.MapGet("/attributes",
[ExcludeFromDescription]
() => "Hello world!");
在控制器型應用程式中, [ApiExplorerSettings] 屬性可用來從 OpenAPI 檔中排除控制器類別中的端點或所有端點。
下列範例示範如何從產生的 OpenAPI 檔中排除端點:
[HttpGet("/private")]
[ApiExplorerSettings(IgnoreApi = true)]
public IActionResult PrivateEndpoint() {
return Ok("This is a private endpoint");
要求或回應主體中使用的 C# 類別或記錄會以所產生 OpenAPI 文件的結構描表示。
預設情況下,架構中只 public 表示屬性,但也可 JsonSerializerOptions 為欄位建立結構屬性。
當 PropertyNamingPolicy 設定為駝峰箱(這是 ASP.NET 網頁應用程式的預設值),結構中的屬性名稱即為類別或記錄屬性名稱的駝峰箱形式。
[JsonPropertyName] 可用於個別屬性,以指定結構描述中的屬性名稱。
JSON 結構描述程式庫會將標準 C# 類型對應至 OpenAPI type 與 format,如下所示:
C# 類型
開放API type
開放API format
請注意,物件和動態類型在 OpenAPI 中 沒有定義類型 ,因為它們可以包含任何類型的數據,包括 int 或 string 等基本類型。
type和format也可以用結構轉換器來設定。 例如,您可能想要把 format 的十進位類型,用 decimal 來取代 double。
ASP.NET 利用類別或記錄屬性的元資料,來設定產生結構對應屬性的元資料。
下列表格摘要屬性,這些屬性來自 System.ComponentModel 命名空間,提供生成的架構所需的中繼資料:
Attribute
Description
請注意,在控制器型應用程式中,這些屬性會將篩選新增至作業,以驗證任何傳入的資料是否符合條件約束。 在最小 API 中,這些屬性會在產生的結構描述中設定中繼資料,但必須透過端點篩選、路由處理常式邏輯或透過第三方套件明確執行驗證。
屬性也可以放在記錄定義的參數清單中,但必須包含 property 修飾詞。 例如:
public record Todo(
[property: Required]
[property: Description("The unique identifier for the todo")]
int Id,
[property: Description("The title of the todo")]
[property: MaxLength(120)]
string Title,
[property: Description("Whether the todo has been completed")]
bool Completed
required
在類別、結構或記錄中,具有 [Required] 屬性或 必要 修飾詞的屬性一律位於 required 對應的結構描述中。
您也可以根據類別、結構或記錄的建構函式(隱含和明確)來要求其他屬性。
對於具有單一公用建構函式的類別或記錄類別,在對應的架構中,任何作為建構函式參數且名稱和類型相同的屬性(不區分大小寫比對)都是必需的。
對於具有多個公用建構函式的類別或記錄類別,不需要其他屬性。
對於結構或記錄結構,不需要其他屬性,因為 C# 一律會定義結構的隱含無參數建構函式。
C# 中的列舉類型是以整數為基礎,但可以使用 JSON 中的 [JsonConverter] 和 JsonStringEnumConverter 表示為字串。 當列舉類型在 JSON 中以字串表示時,產生的結構描述將具有列舉字串值的 enum 屬性。
下列範例示範如何使用 JsonStringEnumConverter 來將列舉表示為 JSON 中的字串:
[JsonConverter(typeof(JsonStringEnumConverter<DayOfTheWeekAsString>))]
public enum DayOfTheWeekAsString
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
特殊案例是當列舉類型具有 [Flags] 屬性時,表示列舉可以視為位字段,也就是一組旗標。 在生成的架構中,具有 [JsonConverterAttribute] 的旗標列舉被定義為 type: string,不含 enum 屬性,這是由於其值可以是列舉值的任意組合。 例如,下列列舉:
[Flags, JsonConverter(typeof(JsonStringEnumConverter<PizzaToppings>))]
public enum PizzaToppings { Pepperoni = 1, Sausage = 2, Mushrooms = 4, Anchovies = 8 }
可能有值,例如"Pepperoni, Sausage"或"Sausage, Mushrooms, Anchovies"。
不含 [JsonConverter] 的列舉類型會在產生的結構描述中定義為 type: integer。
注意:[AllowedValues] 屬性不會設定某個屬性的 enum 值。
可為 Null
在產生的結構描述中,定義為可為 Null 的值或參考型別的屬性會出現 nullable: true。 這與 System.Text.Json 反序列化器的預設行為一致,它接受 null 作為可為 NULL 的屬性的有效值。
additionalProperties
結構定義預設不會產生 additionalProperties 判斷提示,這表示 true 的預設值。 這與 System.Text.Json 還原序列化程式的預設行為一致,它會默默忽略 JSON 物件中的其他屬性。
如果結構描述的其他屬性應該只有特定類型的值,請將屬性或類別定義為 Dictionary<string, type>。 字典的索引鍵類型必須是 string。 這會產生結構描述,其中 additionalProperties 指定 "type" 的結構描述為必要的實值類型。
使用父類別上的 [JsonPolymorphic] 和 [JsonDerivedType] 屬性來指定多型類型的歧視性字段和子類型。
[JsonDerivedType] 將鑑別子欄位新增到每個子類別的結構模式中,並通過列舉來指定每個子類別的特定鑑別子值。 這個屬性也會修改每個衍生類別的建構函式,以設定鑑別子值。
具有 [JsonPolymorphic] 屬性的抽象類別具有 discriminator 結構描述中的欄位,但具有 [JsonPolymorphic] 屬性的實體類別沒有 discriminator 欄位。 OpenAPI 要求鑑別子屬性是結構描述中的必要屬性,但由於實體基底類別中未定義鑑別子屬性,所以結構描述不能包含 discriminator 欄位。
結構描述轉換器可用來覆寫任何預設的中繼資料,或在生成的結構描述中新增其他中繼資料,例如 example 值。 如需詳細資訊,請參閱使用結構描述轉換器。
使用產生的 OpenAPI 文件
OpenAPI 規格