我们使用 NSwag 来使用如下命令生成 swagger 文件:
node_modules/.bin/nswag run foobar.nswag /runtime:NetCore31
这似乎实际上启动了应用程序,并且我们的一些引导代码将失败,因为生成 swagger 文档的进程无法访问连接字符串等。
有没有一种方法可以在不引导/启动整个应用程序的情况下生成文档?
有没有办法在启动代码中检测“swagger 生成模式”,以便我们可以跳过该场景的步骤?
使用
NSwag.AspNetCore
nuget 包版本 13.11.3
foobar.nswag
文件:
{
"runtime": "NetCore31",
"defaultVariables": null,
"documentGenerator": {
"aspNetCoreToOpenApi": {
"project": "Foobar.csproj",
"msBuildProjectExtensionsPath": null,
"configuration": null,
"runtime": null,
"targetFramework": null,
"noBuild": false,
"msBuildOutputPath": null,
"verbose": true,
"workingDirectory": null,
"requireParametersWithoutDefault": false,
"apiGroupNames": [
"BACKEND"
],
"defaultPropertyNameHandling": "Default",
"defaultReferenceTypeNullHandling": "Null",
"defaultDictionaryValueReferenceTypeNullHandling": "NotNull",
"defaultResponseReferenceTypeNullHandling": "NotNull",
"generateOriginalParameterNames": true,
"defaultEnumHandling": "Integer",
"flattenInheritanceHierarchy": false,
"generateKnownTypes": true,
"generateEnumMappingDescription": false,
"generateXmlObjects": false,
"generateAbstractProperties": false,
"generateAbstractSchemas": true,
"ignoreObsoleteProperties": false,
"allowReferencesWithProperties": false,
"excludedTypeNames": [],
"serviceHost": null,
"serviceBasePath": null,
"serviceSchemes": [],
"infoTitle": "My Title",
"infoDescription": null,
"infoVersion": "1.0.0",
"documentTemplate": null,
"documentProcessorTypes": [],
"operationProcessorTypes": [],
"typeNameGeneratorType": null,
"schemaNameGeneratorType": null,
"contractResolverType": null,
"serializerSettingsType": null,
"useDocumentProvider": false,
"documentName": "v1",
"aspNetCoreEnvironment": "Development",
"createWebHostBuilderMethod": null,
"startupType": null,
"allowNullableBodyParameters": true,
"output": "foobar-swagger.json",
"outputType": "Swagger2",
"newLineBehavior": "Auto",
"assemblyPaths": [],
"assemblyConfig": null,
"referencePaths": [],
"useNuGetCache": false
}
},
"codeGenerators": {
"openApiToTypeScriptClient": {
"className": "{controller}Client",
"moduleName": "",
"namespace": "",
"typeScriptVersion": 2.7,
"template": "Fetch",
"promiseType": "Promise",
"httpClass": "HttpClient",
"withCredentials": false,
"useSingletonProvider": false,
"injectionTokenType": "OpaqueToken",
"rxJsVersion": 6.0,
"dateTimeType": "Date",
"nullValue": "Undefined",
"generateClientClasses": false,
"generateClientInterfaces": false,
"generateOptionalParameters": false,
"exportTypes": true,
"wrapDtoExceptions": false,
"exceptionClass": "ApiException",
"clientBaseClass": null,
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"protectedMethods": [],
"configurationClass": null,
"useTransformOptionsMethod": false,
"useTransformResultMethod": false,
"generateDtoTypes": true,
"operationGenerationMode": "MultipleClientsFromOperationId",
"markOptionalProperties": true,
"generateCloneMethod": false,
"typeStyle": "Class",
"enumStyle": "Enum",
"useLeafType": false,
"classTypes": [],
"extendedClasses": [],
"extensionCode": null,
"generateDefaultValues": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateConstructorInterface": true,
"convertConstructorInterfaceData": false,
"importRequiredTypes": true,
"useGetBaseUrlMethod": false,
"baseUrlTokenName": "API_BASE_URL",
"queryNullValue": "",
"useAbortSignal": false,
"inlineNamedDictionaries": false,
"inlineNamedAny": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"checksumCacheEnabled": false,
"serviceHost": null,
"serviceSchemes": null,
"output": null,
"newLineBehavior": "Auto"
}
}
}
我在你的nswag.json中没有看到任何超级奇怪的东西;也许您仍然需要在配置 OpenApi/Swagger 的地方发布 Startup.cs。
您是否可能在
ConfigureServices()
中做一些奇怪的事情,例如运行需要特定设置(如连接字符串)的特定代码。例如?我认为这是一个不好的做法。我也相信 nswag 确实会运行你的项目/运行ConfigureServices()
(但我只是凭记忆猜测),所以这可能会导致问题,是的。
否则,请尝试以下操作:
targetFramework
设置为net5.0
(您使用netcore 3.1,因此需要不同的值),将其留空nobuild
设置为 false
,因为我在运行 nswag
之前构建了我的项目,因为当 nswag 尝试执行此操作或其他问题时,它会随机导致许多问题,项目无法正确构建。the nswag.msbuild
包,并将其全部放在单独的 Api.Client
组件中,并使用 推荐的设置。"configuration": "$(Configuration)"
。我刚刚想出了一个非常丑陋的解决方案,你可能会使用它,但我确实相信这将是一个丑陋的解决方法,因为我认为你的问题在于在ConfigureServices()中使用了不好的做法。
解决方案是在 API 启动时将另一个变量传递给它,或者将环境更改为
Nswag
或类似的东西,这样在你的代码中你可以做类似 if(environment != "nswag") {}
的事情,但同样,丑陋..
我知道有点晚了,但这可能对其他人有帮助。我面临着同样的问题(此处也有描述:https://github.com/RicoSuter/NSwag/issues/3922)
我尝试了使用 nswag.json 中的
createWebHostBuilderMethod
和 startupType
配置的解决方案(此处描述:https://bartwullems.blogspot.com/2021/05/nswag-error-systeminvalidoperationexcep.html),但是对我来说不起作用,因为这些配置现在似乎已经贬值了。
对我有用的是:
NSwag
的自定义配置,仅由 MyApi 项目使用。Program.cs
命名空间和围绕这两个类的 Startup.cs
预编译器指令在 MyApi 项目中创建自定义 NSwag NSwag
和 NSwag
。 Startup
类仅包含控制器和 Swagger 所需的引导,并删除所有其他不相关的引导,特别是那些依赖于运行时应用程序设置的引导。Program.cs
以使用正常或 NSwag 引导。NSwag
配置,即将configuration
设置为NSwag
。MyApi NSwag 程序.cs
#if NSWAG
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace MyApi.NSwag;
public class Program
{
public static void RunHost(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
host.Run();
}
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var builder = WebHost.CreateDefaultBuilder()
.UseStartup<Startup>(); // MyApi.NSwag.Startup
return builder;
}
}
#endif
MyApi NSwag Startup.cs
#if NSWAG
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MyApi.NSwag;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// i.e. whatever you normally have to bootstrap your controllers and Swagger
services.AddControllers();
services.AddVersionedApiExplorer(o =>
{
o.GroupNameFormat = "'v'VVV";
o.SubstituteApiVersionInUrl = true;
})
.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.ReportApiVersions = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ApiVersionReader = new UrlSegmentApiVersionReader();
o.UseApiBehavior = false;
});
services.AddSwaggerDocument(config =>
{
config.DocumentName = "allVersions";
config.Title = "My API";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseOpenApi();
app.UseSwaggerUi3();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
#endif
MyApi 主程序.cs
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace MyApi;
public class Program
{
public static void Main(string[] args)
{
#if NSWAG
NSwag.Program.RunHost(args);
#else
RunHost(args);
#endif
}
private static void RunHost(string[] args)
{
// i.e. whatever you normally have in Main
var host = CreateWebHostBuilder(args).Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var builder = WebHost.CreateDefaultBuilder()
.UseStartup<Startup>(); // MyApi.Startup
return builder;
}
}
MyApi nswag.json
{
"runtime": "Net60",
"defaultVariables": null,
"documentGenerator": {
"aspNetCoreToOpenApi": {
"project": "src/MyApi/MyApi.csproj",
"msBuildProjectExtensionsPath": null,
"configuration": "NSwag",
...
},
...
}
因此,如果您使用
Nswag.MsBuild
nuget 包,您可以在 csproj 中执行构建步骤,例如:
<Target Name="NSwag" AfterTargets="PostBuildEvent" Condition=" '$(Configuration)' == 'Debug' ">
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Nswag" Command="$(NSwagExe_Net50) run nswag.json /variables:Configuration=$(Configuration)" />
</Target>
注意
EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Nswag"
属性。这允许您检查“Nswag”环境变量是否存在并相应地更改您的启动逻辑:
var nswag = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (!string.IsNullOrWhiteSpace(nswag)) {
// just for nswag, do not encrypt as this breaks the build and release pipeline
configurationBuilder.AddJsonFile(source => {
source.ReloadOnChange = true;
source.Path = protectedJsonFile;
});
return;
}
而且您也不需要使用
ASPNETCORE_ENVIRONMENT
作为变量名称,它可以是任何名称。