.NET 5 - SWAGGER.json
.NET 5 - SWAGGER.json
我已经为我的 public api 生成了一个 swagger.json 文件。使用以下代码效果非常好:
在启动中 - 配置服务
//Register Swagger Options as Dependency Injection
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options =>
{
// add a custom operation filter which sets default values
//options.OperationFilter<SwaggerDefaultValues>();
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
});
正在启动 - 配置
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.InjectStylesheet("../css/customize-swagger-ui.css");
c.InjectJavascript("../js/customize-swagger-ui.js");
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
我的问题是,我想在 API-Request 后面添加方法的名称。否则,用于客户端代码生成的 NSWAG 等工具会创建许多不同的方法,这些方法称为 APIRoute1、APIRoute2、APIRoute3、...
这是 swagger 生成文件的 json 片段:
"paths": {
"/api/v1/Order": {
"post": {
"tags": [
"Order"
],
"summary": "Creates a new Order if no order currently exists",
"requestBody": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
}
}
},
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/api/v1/Order/{orderNumber}": {
"get": {
"tags": [
"Order"
],
"summary": "Reads a given Order if exists",
"parameters": [
{
"name": "orderNumber",
"in": "path",
"description": "Order Number",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OrderDTO"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
APIRoute只是一个占位符作为例子。 APIRouteX 背后的方法是用相同的路由实现的,但 http 变量不同,如 (POST, DELETE, PUT)。所以真的很难阅读客户端代码生成的代码。
是否可以在swagger.json文件的路由后面添加“Method-Name”?
SWAGGER 配置选项
/// <summary>
/// Configures the Swagger Options like Titel, Contact Informations etc
/// </summary>
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider;
/// <summary>
/// Constructor which adds ApiVersionDescription by Dependency Injection
/// </summary>
/// <param name="provider">API Version Description Provider</param>
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;
/// <summary>
/// Adds a seperate Swagger Document for each API Version
/// </summary>
/// <param name="options">Swagger Generic Options</param>
public void Configure(SwaggerGenOptions options)
{
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description.ApiVersion.ToString(), description.IsDeprecated));
}
}
/// <summary>
/// Creates Header Informations for API
/// </summary>
/// <param name="description">ApiVersionDescription</param>
/// <returns>Api Info</returns>
static OpenApiInfo CreateInfoForApiVersion(string version, bool isDeprecated)
{
var info = new OpenApiInfo()
{
Title = "Rüstkontrolle API",
Version = version,
Description = "Service Dokumentation für das AddOn Rüstkontrolle im SICK Werkerportal",
Contact = new OpenApiContact() { Name = "Lukas Adler", Email = "lukas.adler@sick.de" },
License = new OpenApiLicense() { Name = "",}
};
if (isDeprecated)
{
info.Description += "API version is deprecated.";
}
return info;
}
}
Swagger 默认值
/// <summary>
/// Swagger Operation Filter
/// </summary>
public class SwaggerDefaultValues : IOperationFilter
{
/// <summary>
/// Applies Operations and OperationsFilterContext on API Descriptions
/// </summary>
/// <param name="operation">Operation</param>
/// <param name="context">OperationFilterContext</param>
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var apiDescription = context.ApiDescription;
if (operation.Parameters == null)
{
return;
}
foreach (var parameter in operation.Parameters)
{
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
if (parameter.Description == null)
{
parameter.Description = description.ModelMetadata?.Description;
}
parameter.Required |= description.IsRequired;
}
}
}
NSWAG 配置
{
"runtime": "NetCore21",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": "HERE IS NORMALLY MY API DESCRIPTION",
"url": "https://localhost:44314/swagger/v1/swagger.json",
"output": null,
"newLineBehavior": "Auto"
}
},
"codeGenerators": {
"openApiToCSharpClient": {
"clientBaseClass": null,
"configurationClass": null,
"generateClientClasses": true,
"generateClientInterfaces": false,
"clientBaseInterface": null,
"injectHttpClient": true,
"disposeHttpClient": true,
"protectedMethods": [],
"generateExceptionClasses": true,
"exceptionClass": "ApiException",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": false,
"useBaseUrl": true,
"generateBaseUrlProperty": true,
"generateSyncMethods": false,
"generatePrepareRequestAndProcessResponseAsAsyncMethods": false,
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"parameterDateFormat": "yyyy-MM-dd",
"generateUpdateJsonSerializerSettingsMethod": true,
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "{controller}Client",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
"additionalContractNamespaceUsages": [],
"generateOptionalParameters": false,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"namespace": "MyNamespace",
"requiredPropertiesMustBeDefined": true,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"jsonLibrary": "NewtonsoftJson",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": null,
"newLineBehavior": "Auto"
}
}
}
在 NSWag 设置中,operationGenerationMode
设置为 MultipleClientsFromOperationId
:
From the first operation tag and operation ID (operation name = operation ID, client name = first operation tag).
但是 OpenAPI 合同(swagger.json 您的文件)没有指定操作的 ID。
我看到两个解决方案,选择其他值 operationGenerationMode
或指定操作的 id。
其他 operationGenerationMode
值 are :
public enum OperationGenerationMode
{
/// <summary>Multiple clients from the Swagger operation ID in the form '{controller}_{action}'.</summary>
MultipleClientsFromOperationId,
/// <summary>From path segments (operation name = last segment, client name = second to last segment).</summary>
MultipleClientsFromPathSegments,
/// <summary>From the first operation tag and path segments (operation name = last segment, client name = first operation tag).</summary>
MultipleClientsFromFirstTagAndPathSegments,
/// <summary>From the first operation tag and operation ID (operation name = operation ID, client name = first operation tag).</summary>
MultipleClientsFromFirstTagAndOperationId,
/// <summary>From the Swagger operation ID.</summary>
SingleClientFromOperationId,
/// <summary>From path segments suffixed by HTTP operation name</summary>
SingleClientFromPathSegments,
}
如果你喜欢指定操作的id,你可以在Http[Get|Put|...]Attribute
中设置名称:
[HttpGet(Name = "SpecifiedOperationId")]
public IActionResult Get()
您可以使用 SwaggerGenOptions.CustomOperationIds
指定您自己的自定义操作 ID。例如。我使用以下设置:
services.AddSwaggerGen(c =>
{
c.CustomOperationIds(x => ${x.ActionDescriptor.RouteValues["controller"]}_{x.ActionDescriptor.RouteValues["action"]}");
});
这会创建类似于 Client_GetDetail
的操作 ID,您可以配置 NSWAG 以创建类似于 clientApi.getDetail()
.
的客户端 API
PS 您正在使用 Swashbuckle in your project, if you use NSwag 那么它应该默认设置它。
我已经为我的 public api 生成了一个 swagger.json 文件。使用以下代码效果非常好:
在启动中 - 配置服务
//Register Swagger Options as Dependency Injection
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options =>
{
// add a custom operation filter which sets default values
//options.OperationFilter<SwaggerDefaultValues>();
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
});
正在启动 - 配置
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.InjectStylesheet("../css/customize-swagger-ui.css");
c.InjectJavascript("../js/customize-swagger-ui.js");
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
我的问题是,我想在 API-Request 后面添加方法的名称。否则,用于客户端代码生成的 NSWAG 等工具会创建许多不同的方法,这些方法称为 APIRoute1、APIRoute2、APIRoute3、...
这是 swagger 生成文件的 json 片段:
"paths": {
"/api/v1/Order": {
"post": {
"tags": [
"Order"
],
"summary": "Creates a new Order if no order currently exists",
"requestBody": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateOrderModel"
}
}
}
},
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/api/v1/Order/{orderNumber}": {
"get": {
"tags": [
"Order"
],
"summary": "Reads a given Order if exists",
"parameters": [
{
"name": "orderNumber",
"in": "path",
"description": "Order Number",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OrderDTO"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
APIRoute只是一个占位符作为例子。 APIRouteX 背后的方法是用相同的路由实现的,但 http 变量不同,如 (POST, DELETE, PUT)。所以真的很难阅读客户端代码生成的代码。
是否可以在swagger.json文件的路由后面添加“Method-Name”?
SWAGGER 配置选项
/// <summary>
/// Configures the Swagger Options like Titel, Contact Informations etc
/// </summary>
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider;
/// <summary>
/// Constructor which adds ApiVersionDescription by Dependency Injection
/// </summary>
/// <param name="provider">API Version Description Provider</param>
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;
/// <summary>
/// Adds a seperate Swagger Document for each API Version
/// </summary>
/// <param name="options">Swagger Generic Options</param>
public void Configure(SwaggerGenOptions options)
{
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description.ApiVersion.ToString(), description.IsDeprecated));
}
}
/// <summary>
/// Creates Header Informations for API
/// </summary>
/// <param name="description">ApiVersionDescription</param>
/// <returns>Api Info</returns>
static OpenApiInfo CreateInfoForApiVersion(string version, bool isDeprecated)
{
var info = new OpenApiInfo()
{
Title = "Rüstkontrolle API",
Version = version,
Description = "Service Dokumentation für das AddOn Rüstkontrolle im SICK Werkerportal",
Contact = new OpenApiContact() { Name = "Lukas Adler", Email = "lukas.adler@sick.de" },
License = new OpenApiLicense() { Name = "",}
};
if (isDeprecated)
{
info.Description += "API version is deprecated.";
}
return info;
}
}
Swagger 默认值
/// <summary>
/// Swagger Operation Filter
/// </summary>
public class SwaggerDefaultValues : IOperationFilter
{
/// <summary>
/// Applies Operations and OperationsFilterContext on API Descriptions
/// </summary>
/// <param name="operation">Operation</param>
/// <param name="context">OperationFilterContext</param>
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var apiDescription = context.ApiDescription;
if (operation.Parameters == null)
{
return;
}
foreach (var parameter in operation.Parameters)
{
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
if (parameter.Description == null)
{
parameter.Description = description.ModelMetadata?.Description;
}
parameter.Required |= description.IsRequired;
}
}
}
NSWAG 配置
{
"runtime": "NetCore21",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": "HERE IS NORMALLY MY API DESCRIPTION",
"url": "https://localhost:44314/swagger/v1/swagger.json",
"output": null,
"newLineBehavior": "Auto"
}
},
"codeGenerators": {
"openApiToCSharpClient": {
"clientBaseClass": null,
"configurationClass": null,
"generateClientClasses": true,
"generateClientInterfaces": false,
"clientBaseInterface": null,
"injectHttpClient": true,
"disposeHttpClient": true,
"protectedMethods": [],
"generateExceptionClasses": true,
"exceptionClass": "ApiException",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": false,
"useBaseUrl": true,
"generateBaseUrlProperty": true,
"generateSyncMethods": false,
"generatePrepareRequestAndProcessResponseAsAsyncMethods": false,
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"parameterDateFormat": "yyyy-MM-dd",
"generateUpdateJsonSerializerSettingsMethod": true,
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "{controller}Client",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
"additionalContractNamespaceUsages": [],
"generateOptionalParameters": false,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"namespace": "MyNamespace",
"requiredPropertiesMustBeDefined": true,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"jsonLibrary": "NewtonsoftJson",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": null,
"newLineBehavior": "Auto"
}
}
}
在 NSWag 设置中,operationGenerationMode
设置为 MultipleClientsFromOperationId
:
From the first operation tag and operation ID (operation name = operation ID, client name = first operation tag).
但是 OpenAPI 合同(swagger.json 您的文件)没有指定操作的 ID。
我看到两个解决方案,选择其他值 operationGenerationMode
或指定操作的 id。
其他 operationGenerationMode
值 are :
public enum OperationGenerationMode
{
/// <summary>Multiple clients from the Swagger operation ID in the form '{controller}_{action}'.</summary>
MultipleClientsFromOperationId,
/// <summary>From path segments (operation name = last segment, client name = second to last segment).</summary>
MultipleClientsFromPathSegments,
/// <summary>From the first operation tag and path segments (operation name = last segment, client name = first operation tag).</summary>
MultipleClientsFromFirstTagAndPathSegments,
/// <summary>From the first operation tag and operation ID (operation name = operation ID, client name = first operation tag).</summary>
MultipleClientsFromFirstTagAndOperationId,
/// <summary>From the Swagger operation ID.</summary>
SingleClientFromOperationId,
/// <summary>From path segments suffixed by HTTP operation name</summary>
SingleClientFromPathSegments,
}
如果你喜欢指定操作的id,你可以在Http[Get|Put|...]Attribute
中设置名称:
[HttpGet(Name = "SpecifiedOperationId")]
public IActionResult Get()
您可以使用 SwaggerGenOptions.CustomOperationIds
指定您自己的自定义操作 ID。例如。我使用以下设置:
services.AddSwaggerGen(c =>
{
c.CustomOperationIds(x => ${x.ActionDescriptor.RouteValues["controller"]}_{x.ActionDescriptor.RouteValues["action"]}");
});
这会创建类似于 Client_GetDetail
的操作 ID,您可以配置 NSWAG 以创建类似于 clientApi.getDetail()
.
PS 您正在使用 Swashbuckle in your project, if you use NSwag 那么它应该默认设置它。