From 3ae2da89cd13ed77156cf35f291c80f371812fa1 Mon Sep 17 00:00:00 2001 From: Cristian Pufu Date: Fri, 29 Sep 2023 13:38:23 +0300 Subject: [PATCH 1/4] Add net8.0 target framework --- azure-pipelines.yml | 9 + build/Build.cs | 3 +- build/_build.csproj | 3 +- global.json | 2 +- .../NSwag.ApiDescription.Client.targets | 2 + .../Middlewares/RedirectToIndexMiddleware.cs | 2 +- src/NSwag.AspNetCore/NSwag.AspNetCore.csproj | 11 +- src/NSwag.AspNetCore/NSwag.AspNetCore.nuspec | 11 + .../AspNetCore/AspNetCoreToOpenApiCommand.cs | 3 +- src/NSwag.Commands/NSwag.Commands.csproj | 6 + src/NSwag.Commands/NSwagDocument.cs | 4 + src/NSwag.Commands/Runtime.cs | 3 + src/NSwag.Commands/RuntimeUtilities.cs | 5 + .../NSwag.ConsoleCore.csproj | 7 +- ...wag.Generation.AspNetCore.Tests.Web.csproj | 2 +- .../NSwag.Generation.AspNetCore.Tests.csproj | 6 +- .../NSwag.Generation.AspNetCore.csproj | 8 +- src/NSwag.MSBuild/NSwag.MSBuild.nuspec | 1 + src/NSwag.MSBuild/NSwag.MSBuild.props | 2 + src/NSwag.Npm/bin/nswag.js | 4 +- .../Controllers/ValuesController.cs | 66 ++ .../NSwag.Sample.NET80.csproj | 12 + src/NSwag.Sample.NET80/Program.cs | 20 + .../Properties/launchSettings.json | 14 + src/NSwag.Sample.NET80/Startup.cs | 65 ++ .../appsettings.Development.json | 9 + src/NSwag.Sample.NET80/appsettings.json | 9 + src/NSwag.Sample.NET80/nswag.json | 58 ++ src/NSwag.Sample.NET80/openapi.json | 215 +++++++ .../GeneratedClientsCs.gen | 603 ++++++++++++++++++ .../GeneratedClientsTs.gen | 183 ++++++ .../GeneratedControllersCs.gen | 140 ++++ .../NSwag.Sample.NET80Minimal.csproj | 8 + src/NSwag.Sample.NET80Minimal/Program.cs | 48 ++ .../Properties/launchSettings.json | 14 + src/NSwag.Sample.NET80Minimal/nswag.json | 227 +++++++ src/NSwag.Sample.NET80Minimal/openapi.json | 95 +++ src/NSwag.sln | 32 +- 38 files changed, 1899 insertions(+), 13 deletions(-) create mode 100644 src/NSwag.Sample.NET80/Controllers/ValuesController.cs create mode 100644 src/NSwag.Sample.NET80/NSwag.Sample.NET80.csproj create mode 100644 src/NSwag.Sample.NET80/Program.cs create mode 100644 src/NSwag.Sample.NET80/Properties/launchSettings.json create mode 100644 src/NSwag.Sample.NET80/Startup.cs create mode 100644 src/NSwag.Sample.NET80/appsettings.Development.json create mode 100644 src/NSwag.Sample.NET80/appsettings.json create mode 100644 src/NSwag.Sample.NET80/nswag.json create mode 100644 src/NSwag.Sample.NET80/openapi.json create mode 100644 src/NSwag.Sample.NET80Minimal/GeneratedClientsCs.gen create mode 100644 src/NSwag.Sample.NET80Minimal/GeneratedClientsTs.gen create mode 100644 src/NSwag.Sample.NET80Minimal/GeneratedControllersCs.gen create mode 100644 src/NSwag.Sample.NET80Minimal/NSwag.Sample.NET80Minimal.csproj create mode 100644 src/NSwag.Sample.NET80Minimal/Program.cs create mode 100644 src/NSwag.Sample.NET80Minimal/Properties/launchSettings.json create mode 100644 src/NSwag.Sample.NET80Minimal/nswag.json create mode 100644 src/NSwag.Sample.NET80Minimal/openapi.json diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 639817b139..c6831b89fb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -39,6 +39,15 @@ steps: performMultiLevelLookup: true useGlobalJson: true +- task: UseDotNet@2 + displayName: 'Install .NET Core SDK' + inputs: + packageType: 'sdk' + version: '8.0.100-rc.1.23463.5' + includePreviewVersions: true + performMultiLevelLookup: true + useGlobalJson: true + - task: CmdLine@2 displayName: 'Install DNT' inputs: diff --git a/build/Build.cs b/build/Build.cs index b3257b1c58..6576d0086d 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -236,7 +236,7 @@ void PublishConsoleProject(Project project, string[] targetFrameworks) PublishConsoleProject(consoleX86Project, new[] { "net462" }); PublishConsoleProject(consoleProject, new[] { "net462" }); - PublishConsoleProject(consoleCoreProject, new[] { "net6.0", "net7.0" }); + PublishConsoleProject(consoleCoreProject, new[] { "net6.0", "net7.0", "net8.0" }); void CopyConsoleBinaries(AbsolutePath target) { @@ -250,6 +250,7 @@ void CopyConsoleBinaries(AbsolutePath target) var consoleCoreDirectory = consoleCoreProject.Directory / "bin" / Configuration; CopyDirectoryRecursively(consoleCoreDirectory / "net6.0" / "publish", target / "Net60"); CopyDirectoryRecursively(consoleCoreDirectory / "net7.0" / "publish", target / "Net70"); + CopyDirectoryRecursively(consoleCoreDirectory / "net8.0" / "publish", target / "Net80"); } Serilog.Log.Information("Copy published Console for NSwagStudio"); diff --git a/build/_build.csproj b/build/_build.csproj index 95d236e770..bfbafd8ebf 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -2,12 +2,13 @@ Exe - net7.0 + net8.0 CS0649;CS0169 .. .. 1 + true diff --git a/global.json b/global.json index 4037c7755e..ada2e61fcf 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100", + "version": "8.0.100-rc.1.23463.5", "rollForward": "latestMinor" } } \ No newline at end of file diff --git a/src/NSwag.ApiDescription.Client/NSwag.ApiDescription.Client.targets b/src/NSwag.ApiDescription.Client/NSwag.ApiDescription.Client.targets index 1e4bb9fd77..ed58a7a7e2 100644 --- a/src/NSwag.ApiDescription.Client/NSwag.ApiDescription.Client.targets +++ b/src/NSwag.ApiDescription.Client/NSwag.ApiDescription.Client.targets @@ -8,6 +8,8 @@ Condition="'$(TargetFramework)' == 'net6.0'">dotnet --roll-forward-on-no-candidate-fx 2 "$(NSwagDir_Net60)/dotnet-nswag.dll" <_NSwagCommand Condition="'$(TargetFramework)' == 'net7.0'">dotnet --roll-forward-on-no-candidate-fx 2 "$(NSwagDir_Net70)/dotnet-nswag.dll" + <_NSwagCommand + Condition="'$(TargetFramework)' == 'net8.0'">dotnet --roll-forward-on-no-candidate-fx 2 "$(NSwagDir_Net80)/dotnet-nswag.dll" diff --git a/src/NSwag.AspNetCore/Middlewares/RedirectToIndexMiddleware.cs b/src/NSwag.AspNetCore/Middlewares/RedirectToIndexMiddleware.cs index 50b1df1b22..28136dbc6c 100644 --- a/src/NSwag.AspNetCore/Middlewares/RedirectToIndexMiddleware.cs +++ b/src/NSwag.AspNetCore/Middlewares/RedirectToIndexMiddleware.cs @@ -40,7 +40,7 @@ public async Task Invoke(HttpContext context) var suffix = !string.IsNullOrWhiteSpace(_swaggerRoute) ? "?url=" + _transformToExternal(_swaggerRoute, context.Request) : ""; var path = _transformToExternal(_swaggerUiRoute, context.Request); - context.Response.Headers.Add("Location", (path != "/" ? path : "") + "/index.html" + suffix); + context.Response.Headers.Append("Location", (path != "/" ? path : "") + "/index.html" + suffix); } else { diff --git a/src/NSwag.AspNetCore/NSwag.AspNetCore.csproj b/src/NSwag.AspNetCore/NSwag.AspNetCore.csproj index b982a4e719..e06127980e 100644 --- a/src/NSwag.AspNetCore/NSwag.AspNetCore.csproj +++ b/src/NSwag.AspNetCore/NSwag.AspNetCore.csproj @@ -1,6 +1,6 @@  - net462;netstandard2.0;net6.0;net7.0 + net462;netstandard2.0;net6.0;net7.0;net8.0 Swagger Documentation AspNetCore NetCore TypeScript CodeGen $(MSBuildProjectName).nuspec symbols.nupkg @@ -17,6 +17,7 @@ [5, 6.0) [6.0.0, 7.0) [7.0.0, 8.0) + 8.0.0-rc.1.23421.29 1.6.1 4.3.0 4.0.1 @@ -54,7 +55,12 @@ - + + + + + + @@ -81,6 +87,7 @@ microsoftExtensionsFileProvidersEmbeddedPackageVersionNet5=$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersionNet5); microsoftExtensionsFileProvidersEmbeddedPackageVersionNet6=$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersionNet6); microsoftExtensionsFileProvidersEmbeddedPackageVersionNet7=$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersionNet7); + microsoftExtensionsFileProvidersEmbeddedPackageVersionNet8=$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersionNet8); netStandardLibraryPackageVersion=$(NETStandardLibraryPackageVersion); systemIOFileSystemPackageVersion=$(SystemIOFileSystemPackageVersion); systemXmlXPathXDocumentPackageVersion=$(SystemXmlXPathXDocumentPackageVersion); diff --git a/src/NSwag.AspNetCore/NSwag.AspNetCore.nuspec b/src/NSwag.AspNetCore/NSwag.AspNetCore.nuspec index 9a6d32a5df..286c9aa1e1 100644 --- a/src/NSwag.AspNetCore/NSwag.AspNetCore.nuspec +++ b/src/NSwag.AspNetCore/NSwag.AspNetCore.nuspec @@ -55,6 +55,15 @@ + + + + + + + + + @@ -69,5 +78,7 @@ + + diff --git a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs index f3e1c780dc..d27fd5f585 100644 --- a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs +++ b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs @@ -145,7 +145,8 @@ public override async Task RunAsync(CommandLineProcessor processor, ICon if (projectMetadata.TargetFrameworkIdentifier == ".NETCoreApp" || projectMetadata.TargetFrameworkIdentifier == "net6.0" || - projectMetadata.TargetFrameworkIdentifier == "net7.0") + projectMetadata.TargetFrameworkIdentifier == "net7.0" || + projectMetadata.TargetFrameworkIdentifier == "net8.0") { executable = "dotnet"; args.Add("exec"); diff --git a/src/NSwag.Commands/NSwag.Commands.csproj b/src/NSwag.Commands/NSwag.Commands.csproj index 64cc900a02..4c3e9b028f 100644 --- a/src/NSwag.Commands/NSwag.Commands.csproj +++ b/src/NSwag.Commands/NSwag.Commands.csproj @@ -22,6 +22,12 @@ + + + + + + diff --git a/src/NSwag.Commands/NSwagDocument.cs b/src/NSwag.Commands/NSwagDocument.cs index 7f4526821a..fb4450afe8 100644 --- a/src/NSwag.Commands/NSwagDocument.cs +++ b/src/NSwag.Commands/NSwagDocument.cs @@ -247,6 +247,10 @@ private string GetArgumentsPrefix() { return "\"" + System.IO.Path.Combine(RootBinaryDirectory, "Net70/dotnet-nswag.dll") + "\" "; } + else if (runtime == Runtime.Net80) + { + return "\"" + System.IO.Path.Combine(RootBinaryDirectory, "Net80/dotnet-nswag.dll") + "\" "; + } else #endif return ""; diff --git a/src/NSwag.Commands/Runtime.cs b/src/NSwag.Commands/Runtime.cs index 63b5569335..1b2a9ed712 100644 --- a/src/NSwag.Commands/Runtime.cs +++ b/src/NSwag.Commands/Runtime.cs @@ -25,6 +25,9 @@ public enum Runtime /// .NET 7 app. Net70, + + /// .NET 8 app. + Net80, /// Execute in the same process. Debug diff --git a/src/NSwag.Commands/RuntimeUtilities.cs b/src/NSwag.Commands/RuntimeUtilities.cs index 71370da34d..f0b9f33d68 100644 --- a/src/NSwag.Commands/RuntimeUtilities.cs +++ b/src/NSwag.Commands/RuntimeUtilities.cs @@ -25,6 +25,11 @@ public static Runtime CurrentRuntime var framework = PlatformServices.Default.Application.RuntimeFramework; if (framework.Identifier == ".NETCoreApp") { + if (framework.Version.Major >= 8) + { + return Runtime.Net80; + } + if (framework.Version.Major >= 7) { return Runtime.Net70; diff --git a/src/NSwag.ConsoleCore/NSwag.ConsoleCore.csproj b/src/NSwag.ConsoleCore/NSwag.ConsoleCore.csproj index 616cd42a2e..48045b6dd5 100644 --- a/src/NSwag.ConsoleCore/NSwag.ConsoleCore.csproj +++ b/src/NSwag.ConsoleCore/NSwag.ConsoleCore.csproj @@ -1,6 +1,6 @@  - net6.0;net7.0 + net6.0;net7.0;net8.0 Exe dotnet-nswag NSwag.ConsoleCore @@ -22,6 +22,11 @@ + + + + + diff --git a/src/NSwag.Generation.AspNetCore.Tests.Web/NSwag.Generation.AspNetCore.Tests.Web.csproj b/src/NSwag.Generation.AspNetCore.Tests.Web/NSwag.Generation.AspNetCore.Tests.Web.csproj index 347e194d95..dea412e347 100644 --- a/src/NSwag.Generation.AspNetCore.Tests.Web/NSwag.Generation.AspNetCore.Tests.Web.csproj +++ b/src/NSwag.Generation.AspNetCore.Tests.Web/NSwag.Generation.AspNetCore.Tests.Web.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0 + net6.0;net7.0;net8.0 true $(NoWarn),618,1591 enable diff --git a/src/NSwag.Generation.AspNetCore.Tests/NSwag.Generation.AspNetCore.Tests.csproj b/src/NSwag.Generation.AspNetCore.Tests/NSwag.Generation.AspNetCore.Tests.csproj index 7ac1896dad..9eb0d477a9 100644 --- a/src/NSwag.Generation.AspNetCore.Tests/NSwag.Generation.AspNetCore.Tests.csproj +++ b/src/NSwag.Generation.AspNetCore.Tests/NSwag.Generation.AspNetCore.Tests.csproj @@ -1,6 +1,6 @@  - net6.0;net7.0 + net6.0;net7.0;net8.0 $(NoWarn),618,1591 @@ -19,6 +19,10 @@ + + + + diff --git a/src/NSwag.Generation.AspNetCore/NSwag.Generation.AspNetCore.csproj b/src/NSwag.Generation.AspNetCore/NSwag.Generation.AspNetCore.csproj index 5bb32b7b9d..a0df20bcc9 100644 --- a/src/NSwag.Generation.AspNetCore/NSwag.Generation.AspNetCore.csproj +++ b/src/NSwag.Generation.AspNetCore/NSwag.Generation.AspNetCore.csproj @@ -1,6 +1,6 @@ - net462;netstandard2.0;net6.0;net7.0 + net462;netstandard2.0;net6.0;net7.0;net8.0 Swagger Documentation AspNetCore $(DefineConstants);ASPNETCORE bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml @@ -23,6 +23,12 @@ + + + + + + diff --git a/src/NSwag.MSBuild/NSwag.MSBuild.nuspec b/src/NSwag.MSBuild/NSwag.MSBuild.nuspec index dded2467a9..0552d5c9ad 100644 --- a/src/NSwag.MSBuild/NSwag.MSBuild.nuspec +++ b/src/NSwag.MSBuild/NSwag.MSBuild.nuspec @@ -30,5 +30,6 @@ + diff --git a/src/NSwag.MSBuild/NSwag.MSBuild.props b/src/NSwag.MSBuild/NSwag.MSBuild.props index 8cc764e2fe..b70ce45bef 100644 --- a/src/NSwag.MSBuild/NSwag.MSBuild.props +++ b/src/NSwag.MSBuild/NSwag.MSBuild.props @@ -5,9 +5,11 @@ "$(MSBuildThisFileDirectory)../tools/Win/NSwag.x86.exe" dotnet "$(MSBuildThisFileDirectory)../tools/Net60/dotnet-nswag.dll" dotnet "$(MSBuildThisFileDirectory)../tools/Net70/dotnet-nswag.dll" + dotnet "$(MSBuildThisFileDirectory)../tools/Net80/dotnet-nswag.dll" $(MSBuildThisFileDirectory)../tools/Win/ $(MSBuildThisFileDirectory)../tools/Net60/ $(MSBuildThisFileDirectory)../tools/Net70/ + $(MSBuildThisFileDirectory)../tools/Net80/ diff --git a/src/NSwag.Npm/bin/nswag.js b/src/NSwag.Npm/bin/nswag.js index 86f189e4ff..5957bc4202 100644 --- a/src/NSwag.Npm/bin/nswag.js +++ b/src/NSwag.Npm/bin/nswag.js @@ -1,10 +1,11 @@ #!/usr/bin/env node "use strict"; -var defaultCoreVersion = "Net70"; +var defaultCoreVersion = "Net80"; var supportedCoreVersions = [ { ver: '6.0', dir: "Net60", }, { ver: '7.0', dir: "Net70", }, + { ver: '8.0', dir: "Net80", }, ]; // Initialize @@ -17,6 +18,7 @@ args = args.replace("--x86", "/runtime:WinX86"); args = args.replace("/runtime:x86", "/runtime:WinX86"); args = args.replace("--core 6.0", "/runtime:Net60"); args = args.replace("--core 7.0", "/runtime:Net70"); +args = args.replace("--core 8.0", "/runtime:Net80"); args = args.replace("--core", "/runtime:" + defaultCoreVersion); // Search for full .NET installation diff --git a/src/NSwag.Sample.NET80/Controllers/ValuesController.cs b/src/NSwag.Sample.NET80/Controllers/ValuesController.cs new file mode 100644 index 0000000000..7b092f1fed --- /dev/null +++ b/src/NSwag.Sample.NET80/Controllers/ValuesController.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; + +namespace NSwag.Sample.NET80.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ValuesController : ControllerBase + { + public class Person + { + public string FirstName { get; set; } = ""; + + public string? MiddleName { get; set; } + + public string LastName { get; set; } = ""; + + public DateTime DayOfBirth { get; set; } + } + + public enum TestEnum + { + Foo, + Bar + } + + [HttpGet] + public ActionResult> Get() + { + return new Person[] { }; + } + + // GET api/values/5 + [HttpGet("{id}")] + public ActionResult Get(int id) + { + return TestEnum.Foo; + } + + // GET api/values/5 + [HttpGet("{id}/foo")] + public ActionResult GetFooBar(int id) + { + return "value"; + } + + // POST api/values + [HttpPost] + public void Post([FromBody] string value) + { + } + + // PUT api/values/5 + [HttpPut("{id}")] + public void Put(int id, [FromBody] string value) + { + } + + // DELETE api/values/5 + [HttpDelete("{id}")] + public void Delete(int id) + { + } + } +} diff --git a/src/NSwag.Sample.NET80/NSwag.Sample.NET80.csproj b/src/NSwag.Sample.NET80/NSwag.Sample.NET80.csproj new file mode 100644 index 0000000000..ac767436e5 --- /dev/null +++ b/src/NSwag.Sample.NET80/NSwag.Sample.NET80.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + + + + + + + diff --git a/src/NSwag.Sample.NET80/Program.cs b/src/NSwag.Sample.NET80/Program.cs new file mode 100644 index 0000000000..3a722a0021 --- /dev/null +++ b/src/NSwag.Sample.NET80/Program.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace NSwag.Sample.NET80 +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/src/NSwag.Sample.NET80/Properties/launchSettings.json b/src/NSwag.Sample.NET80/Properties/launchSettings.json new file mode 100644 index 0000000000..b9ab13135c --- /dev/null +++ b/src/NSwag.Sample.NET80/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "NSwag.Sample.NET70": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:7001;http://localhost:7000" + } + } +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80/Startup.cs b/src/NSwag.Sample.NET80/Startup.cs new file mode 100644 index 0000000000..dcfceea65d --- /dev/null +++ b/src/NSwag.Sample.NET80/Startup.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NJsonSchema.Generation; +using System.Text.Json.Serialization; + +namespace NSwag.Sample.NET80 +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc(); + + services + .AddControllers() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + + services.AddOpenApiDocument(document => + { + document.Description = "Hello world!"; + document.SchemaSettings.DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull; + }); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + app.UseOpenApi(p => p.Path = "/swagger/{documentName}/swagger.yaml"); + app.UseSwaggerUi3(p => p.DocumentPath = "/swagger/{documentName}/swagger.yaml"); + //app.UseApimundo(); + app.UseApimundo(settings => + { + //settings.CompareTo = "a:a:27:25:15:latest"; + settings.DocumentPath = "/swagger/v1/swagger.yaml"; + settings.ApimundoUrl = "https://localhost:5001"; + }); + } + } +} diff --git a/src/NSwag.Sample.NET80/appsettings.Development.json b/src/NSwag.Sample.NET80/appsettings.Development.json new file mode 100644 index 0000000000..e203e9407e --- /dev/null +++ b/src/NSwag.Sample.NET80/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/NSwag.Sample.NET80/appsettings.json b/src/NSwag.Sample.NET80/appsettings.json new file mode 100644 index 0000000000..7cb5ac8193 --- /dev/null +++ b/src/NSwag.Sample.NET80/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/src/NSwag.Sample.NET80/nswag.json b/src/NSwag.Sample.NET80/nswag.json new file mode 100644 index 0000000000..f0db6bf230 --- /dev/null +++ b/src/NSwag.Sample.NET80/nswag.json @@ -0,0 +1,58 @@ +{ + "runtime": "Net80", + "defaultVariables": null, + "documentGenerator": { + "aspNetCoreToOpenApi": { + "project": "NSwag.Sample.NET80.csproj", + "msBuildProjectExtensionsPath": null, + "configuration": null, + "runtime": null, + "targetFramework": null, + "noBuild": false, + "verbose": true, + "workingDirectory": null, + "requireParametersWithoutDefault": false, + "apiGroupNames": null, + "defaultPropertyNameHandling": "Default", + "defaultReferenceTypeNullHandling": "Null", + "defaultDictionaryValueReferenceTypeNullHandling": "NotNull", + "defaultResponseReferenceTypeNullHandling": "NotNull", + "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": true, + "documentName": "v1", + "aspNetCoreEnvironment": null, + "createWebHostBuilderMethod": null, + "startupType": null, + "allowNullableBodyParameters": true, + "output": "openapi.json", + "outputType": "Swagger2", + "assemblyPaths": [], + "assemblyConfig": null, + "referencePaths": [], + "useNuGetCache": false + } + }, + "codeGenerators": {} +} diff --git a/src/NSwag.Sample.NET80/openapi.json b/src/NSwag.Sample.NET80/openapi.json new file mode 100644 index 0000000000..26c94bf3b5 --- /dev/null +++ b/src/NSwag.Sample.NET80/openapi.json @@ -0,0 +1,215 @@ +{ + "x-generator": "NSwag v14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))", + "openapi": "3.0.0", + "info": { + "title": "My Title", + "description": "Hello world!", + "version": "1.0.0" + }, + "paths": { + "/api/Values": { + "get": { + "tags": [ + "Values" + ], + "operationId": "Values_GetAll", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Person" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Values" + ], + "operationId": "Values_Post", + "requestBody": { + "x-name": "value", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "200": { + "description": "" + } + } + } + }, + "/api/Values/{id}": { + "get": { + "tags": [ + "Values" + ], + "operationId": "Values_Get", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestEnum" + } + } + } + } + } + }, + "put": { + "tags": [ + "Values" + ], + "operationId": "Values_Put", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "value", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "" + } + } + }, + "delete": { + "tags": [ + "Values" + ], + "operationId": "Values_Delete", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/api/Values/{id}/foo": { + "get": { + "tags": [ + "Values" + ], + "operationId": "Values_GetFooBar", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Person": { + "type": "object", + "additionalProperties": false, + "properties": { + "firstName": { + "type": "string" + }, + "middleName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string" + }, + "dayOfBirth": { + "type": "string", + "format": "date-time" + } + } + }, + "TestEnum": { + "type": "string", + "description": "", + "x-enumNames": [ + "Foo", + "Bar" + ], + "enum": [ + "Foo", + "Bar" + ] + } + } + } +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/GeneratedClientsCs.gen b/src/NSwag.Sample.NET80Minimal/GeneratedClientsCs.gen new file mode 100644 index 0000000000..d18300d06f --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/GeneratedClientsCs.gen @@ -0,0 +1,603 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" + +namespace MyNamespace +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Client + { + private string _baseUrl = ""; + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + + public Client(string baseUrl, System.Net.Http.HttpClient httpClient) + { + BaseUrl = baseUrl; + _httpClient = httpClient; + } + + private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAsync() + { + return GetAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CalculateSumAsync(int a, int b) + { + return CalculateSumAsync(a, b, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CalculateSumAsync(int a, int b, System.Threading.CancellationToken cancellationToken) + { + if (a == null) + throw new System.ArgumentNullException("a"); + + if (b == null) + throw new System.ArgumentNullException("b"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sum/{a}/{b}"); + urlBuilder_.Replace("{a}", System.Uri.EscapeDataString(ConvertToString(a, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{b}", System.Uri.EscapeDataString(ConvertToString(b, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ExampleClient + { + private string _baseUrl = ""; + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + + public ExampleClient(string baseUrl, System.Net.Http.HttpClient httpClient) + { + BaseUrl = baseUrl; + _httpClient = httpClient; + } + + private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAsync() + { + return GetAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/examples"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await response_.Content.ReadAsStreamAsync().ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileResponse : System.IDisposable + { + private System.IDisposable _client; + private System.IDisposable _response; + + public int StatusCode { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public System.IO.Stream Stream { get; private set; } + + public bool IsPartial + { + get { return StatusCode == 206; } + } + + public FileResponse(int statusCode, System.Collections.Generic.IReadOnlyDictionary> headers, System.IO.Stream stream, System.IDisposable client, System.IDisposable response) + { + StatusCode = statusCode; + Headers = headers; + Stream = stream; + _client = client; + _response = response; + } + + public void Dispose() + { + Stream.Dispose(); + if (_response != null) + _response.Dispose(); + if (_client != null) + _client.Dispose(); + } + } + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8603 +#pragma warning restore 8604 \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/GeneratedClientsTs.gen b/src/NSwag.Sample.NET80Minimal/GeneratedClientsTs.gen new file mode 100644 index 0000000000..cf3c9f5ec4 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/GeneratedClientsTs.gen @@ -0,0 +1,183 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +/* tslint:disable */ +/* eslint-disable */ +// ReSharper disable InconsistentNaming + +export class Client { + private http: { fetch(url: RequestInfo, init?: RequestInit): Promise }; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise }) { + this.http = http ? http : window as any; + this.baseUrl = baseUrl ?? ""; + } + + get(): Promise { + let url_ = this.baseUrl + "/"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGet(_response); + }); + } + + protected processGet(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = resultData200 !== undefined ? resultData200 : null; + + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } + + calculateSum(a: number, b: number): Promise { + let url_ = this.baseUrl + "/sum/{a}/{b}"; + if (a === undefined || a === null) + throw new Error("The parameter 'a' must be defined."); + url_ = url_.replace("{a}", encodeURIComponent("" + a)); + if (b === undefined || b === null) + throw new Error("The parameter 'b' must be defined."); + url_ = url_.replace("{b}", encodeURIComponent("" + b)); + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processCalculateSum(_response); + }); + } + + protected processCalculateSum(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = resultData200 !== undefined ? resultData200 : null; + + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } +} + +export class ExampleClient { + private http: { fetch(url: RequestInfo, init?: RequestInit): Promise }; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise }) { + this.http = http ? http : window as any; + this.baseUrl = baseUrl ?? ""; + } + + get(): Promise { + let url_ = this.baseUrl + "/examples"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/octet-stream" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGet(_response); + }); + } + + protected processGet(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined; + let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined; + if (fileName) { + fileName = decodeURIComponent(fileName); + } else { + fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + } + return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } +} + +export interface FileResponse { + data: Blob; + status: number; + fileName?: string; + headers?: { [name: string]: any }; +} + +export class ApiException extends Error { + message: string; + status: number; + response: string; + headers: { [key: string]: any; }; + result: any; + + constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) { + super(); + + this.message = message; + this.status = status; + this.response = response; + this.headers = headers; + this.result = result; + } + + protected isApiException = true; + + static isApiException(obj: any): obj is ApiException { + return obj.isApiException === true; + } +} + +function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any { + if (result !== null && result !== undefined) + throw result; + else + throw new ApiException(message, status, response, headers, null); +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/GeneratedControllersCs.gen b/src/NSwag.Sample.NET80Minimal/GeneratedControllersCs.gen new file mode 100644 index 0000000000..e894d64074 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/GeneratedControllersCs.gen @@ -0,0 +1,140 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" + +namespace MyNamespace +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public interface IController + { + + System.Threading.Tasks.Task GetAsync(); + + + + System.Threading.Tasks.Task CalculateSumAsync(int a, int b); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + + public partial class Controller : Microsoft.AspNetCore.Mvc.ControllerBase + { + private IController _implementation; + + public Controller(IController implementation) + { + _implementation = implementation; + } + + [Microsoft.AspNetCore.Mvc.HttpGet, Microsoft.AspNetCore.Mvc.Route("")] + public System.Threading.Tasks.Task Get() + { + + return _implementation.GetAsync(); + } + + [Microsoft.AspNetCore.Mvc.HttpGet, Microsoft.AspNetCore.Mvc.Route("sum/{a}/{b}")] + public System.Threading.Tasks.Task CalculateSum(int a, int b) + { + + return _implementation.CalculateSumAsync(a, b); + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public interface IExampleController + { + + System.Threading.Tasks.Task GetAsync(); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + + public partial class ExampleController : Microsoft.AspNetCore.Mvc.ControllerBase + { + private IExampleController _implementation; + + public ExampleController(IExampleController implementation) + { + _implementation = implementation; + } + + [Microsoft.AspNetCore.Mvc.HttpGet, Microsoft.AspNetCore.Mvc.Route("examples")] + public System.Threading.Tasks.Task Get() + { + + return _implementation.GetAsync(); + } + + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileResponse : System.IDisposable + { + private System.IDisposable _client; + private System.IDisposable _response; + + public int StatusCode { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public System.IO.Stream Stream { get; private set; } + + public bool IsPartial + { + get { return StatusCode == 206; } + } + + public FileResponse(int statusCode, System.Collections.Generic.IReadOnlyDictionary> headers, System.IO.Stream stream, System.IDisposable client, System.IDisposable response) + { + StatusCode = statusCode; + Headers = headers; + Stream = stream; + _client = client; + _response = response; + } + + public void Dispose() + { + Stream.Dispose(); + if (_response != null) + _response.Dispose(); + if (_client != null) + _client.Dispose(); + } + } + + + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8603 +#pragma warning restore 8604 \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/NSwag.Sample.NET80Minimal.csproj b/src/NSwag.Sample.NET80Minimal/NSwag.Sample.NET80Minimal.csproj new file mode 100644 index 0000000000..fda6332495 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/NSwag.Sample.NET80Minimal.csproj @@ -0,0 +1,8 @@ + + + net8.0 + + + + + diff --git a/src/NSwag.Sample.NET80Minimal/Program.cs b/src/NSwag.Sample.NET80Minimal/Program.cs new file mode 100644 index 0000000000..7a6b363fa4 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/Program.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using System; + +var builder = WebApplication.CreateBuilder(args); + +// Optional: Use controllers +builder.Services.AddControllers(); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddOpenApiDocument(settings => +{ + settings.Title = "Minimal API"; + settings.Version = "v1"; +}); + +var app = builder.Build(); +app.UseDeveloperExceptionPage(); + +app.UseOpenApi(); +app.UseSwaggerUi3(); + +app.MapGet("/", (Func)(() => "Hello World!")) + .WithTags("General"); + +app.MapGet("/sum/{a}/{b}", (Func)((a, b) => a + b)) + .WithName("CalculateSum") + .WithTags("Calculator"); + +// Optional: Use controllers +app.UseRouting(); +app.MapControllers(); + +app.Run(); + +// Optional: Use controllers +[ApiController] +[Route("examples")] +public class ExampleController : ControllerBase +{ + [HttpGet] + public IActionResult Get() + { + return Ok("Get Method"); + } +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/Properties/launchSettings.json b/src/NSwag.Sample.NET80Minimal/Properties/launchSettings.json new file mode 100644 index 0000000000..0cfc7c4de2 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "NSwag.Sample.NET80Minimal": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:7001;http://localhost:7000" + } + } +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/nswag.json b/src/NSwag.Sample.NET80Minimal/nswag.json new file mode 100644 index 0000000000..2b2238e1d3 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/nswag.json @@ -0,0 +1,227 @@ +{ + "runtime": "Net80", + "defaultVariables": null, + "documentGenerator": { + "aspNetCoreToOpenApi": { + "project": "NSwag.Sample.NET80Minimal.csproj", + "documentName": "v1", + "msBuildProjectExtensionsPath": null, + "configuration": null, + "runtime": null, + "targetFramework": null, + "noBuild": false, + "msBuildOutputPath": null, + "verbose": true, + "workingDirectory": null, + "aspNetCoreEnvironment": null, + "output": "openapi.json", + "newLineBehavior": "Auto" + } + }, + "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": true, + "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, + "generateTypeCheckFunctions": false, + "generateConstructorInterface": true, + "convertConstructorInterfaceData": false, + "importRequiredTypes": true, + "useGetBaseUrlMethod": false, + "baseUrlTokenName": "API_BASE_URL", + "queryNullValue": "", + "useAbortSignal": false, + "inlineNamedDictionaries": false, + "inlineNamedAny": false, + "includeHttpContext": false, + "templateDirectory": null, + "serviceHost": null, + "serviceSchemes": null, + "output": "GeneratedClientsTs.gen", + "newLineBehavior": "Auto" + }, + "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, + "serviceHost": null, + "serviceSchemes": null, + "output": "GeneratedClientsCs.gen", + "newLineBehavior": "Auto" + }, + "openApiToCSharpController": { + "controllerBaseClass": null, + "controllerStyle": "Partial", + "controllerTarget": "AspNetCore", + "useCancellationToken": false, + "useActionResultType": false, + "generateModelValidationAttributes": false, + "routeNamingStrategy": "None", + "basePath": null, + "className": "{controller}", + "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.List", + "arrayInstanceType": "System.Collections.Generic.List", + "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, + "serviceHost": null, + "serviceSchemes": null, + "output": "GeneratedControllersCs.gen", + "newLineBehavior": "Auto" + } + } +} \ No newline at end of file diff --git a/src/NSwag.Sample.NET80Minimal/openapi.json b/src/NSwag.Sample.NET80Minimal/openapi.json new file mode 100644 index 0000000000..1d23f2ea40 --- /dev/null +++ b/src/NSwag.Sample.NET80Minimal/openapi.json @@ -0,0 +1,95 @@ +{ + "x-generator": "NSwag v14.0.0.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))", + "openapi": "3.0.0", + "info": { + "title": "Minimal API", + "version": "v1" + }, + "paths": { + "/": { + "get": { + "tags": [ + "General" + ], + "operationId": "Get", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/sum/{a}/{b}": { + "get": { + "tags": [ + "Calculator" + ], + "operationId": "CalculateSum", + "parameters": [ + { + "name": "a", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 1 + }, + { + "name": "b", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + } + }, + "/examples": { + "get": { + "tags": [ + "Example" + ], + "operationId": "Example_Get", + "responses": { + "200": { + "description": "", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/src/NSwag.sln b/src/NSwag.sln index e8b9d11f6a..1942d2cb6a 100644 --- a/src/NSwag.sln +++ b/src/NSwag.sln @@ -127,7 +127,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSwag.Sample.NET70", "NSwag EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSwag.Sample.NET70Minimal", "NSwag.Sample.NET70Minimal\NSwag.Sample.NET70Minimal.csproj", "{6AE2AAD7-8093-46F4-88BD-CB7439A84EED}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSwag.ConsoleCore.Tests", "NSwag.ConsoleCore.Tests\NSwag.ConsoleCore.Tests.csproj", "{CF6112E5-20FD-4B22-A6C0-20AF6B3396F3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSwag.ConsoleCore.Tests", "NSwag.ConsoleCore.Tests\NSwag.ConsoleCore.Tests.csproj", "{CF6112E5-20FD-4B22-A6C0-20AF6B3396F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSwag.Sample.NET80", "NSwag.Sample.NET80\NSwag.Sample.NET80.csproj", "{2A166077-2189-4376-A38B-8E362A319028}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSwag.Sample.NET80Minimal", "NSwag.Sample.NET80Minimal\NSwag.Sample.NET80Minimal.csproj", "{F0569608-BD55-4316-94F0-E85A14D7FE14}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -549,6 +553,30 @@ Global {CF6112E5-20FD-4B22-A6C0-20AF6B3396F3}.Release|x64.Build.0 = Release|Any CPU {CF6112E5-20FD-4B22-A6C0-20AF6B3396F3}.Release|x86.ActiveCfg = Release|Any CPU {CF6112E5-20FD-4B22-A6C0-20AF6B3396F3}.Release|x86.Build.0 = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|x64.Build.0 = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Debug|x86.Build.0 = Debug|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|Any CPU.Build.0 = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|x64.ActiveCfg = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|x64.Build.0 = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|x86.ActiveCfg = Release|Any CPU + {2A166077-2189-4376-A38B-8E362A319028}.Release|x86.Build.0 = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|x64.ActiveCfg = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|x64.Build.0 = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|x86.ActiveCfg = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Debug|x86.Build.0 = Debug|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|Any CPU.Build.0 = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|x64.ActiveCfg = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|x64.Build.0 = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|x86.ActiveCfg = Release|Any CPU + {F0569608-BD55-4316-94F0-E85A14D7FE14}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -593,6 +621,8 @@ Global {15221E25-4D06-42DB-B3F1-CC9EE721FBAA} = {D8CC0D1C-8DAC-49FE-AA78-C028DC124DD5} {6AE2AAD7-8093-46F4-88BD-CB7439A84EED} = {D8CC0D1C-8DAC-49FE-AA78-C028DC124DD5} {CF6112E5-20FD-4B22-A6C0-20AF6B3396F3} = {F0F26A35-C4B6-42D0-A1DF-98CA46A5C560} + {2A166077-2189-4376-A38B-8E362A319028} = {D8CC0D1C-8DAC-49FE-AA78-C028DC124DD5} + {F0569608-BD55-4316-94F0-E85A14D7FE14} = {D8CC0D1C-8DAC-49FE-AA78-C028DC124DD5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {98FCEEE2-A45C-41E7-B2ED-1B14755E9067} From 2ff4583a8f12c33c1ac3e690667c95fc61ac3be5 Mon Sep 17 00:00:00 2001 From: Cristian Pufu Date: Sat, 30 Sep 2023 13:34:25 +0300 Subject: [PATCH 2/4] Install net8 sdk missing from base image --- .github/workflows/build.yml | 4 ++++ .github/workflows/pr.yml | 4 ++++ build/Build.CI.GitHubActions.cs | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6aacc17d36..62dce5fe9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,10 @@ jobs: run: | echo "Adding GNU tar to PATH" echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 8.0.100-rc.1.23463.5 - uses: actions/checkout@v3 - name: 'Cache: .nuke/temp, ~/.nuget/packages' uses: actions/cache@v3 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d0263df1e9..35edba28e1 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -41,6 +41,10 @@ jobs: run: | echo "Adding GNU tar to PATH" echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 8.0.100-rc.1.23463.5 - uses: actions/checkout@v3 - name: 'Cache: .nuke/temp, ~/.nuget/packages' uses: actions/cache@v3 diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs index c70ae23d14..3bcafab1a7 100644 --- a/build/Build.CI.GitHubActions.cs +++ b/build/Build.CI.GitHubActions.cs @@ -47,6 +47,12 @@ protected override GitHubActionsJob GetJobs(GitHubActionsImage image, IReadOnlyC var newSteps = new List(job.Steps); + // only need to list the ones that are missing from default image + newSteps.Insert(0, new GitHubActionsSetupDotNetStep(new[] + { + "8.0.100-rc.1.23463.5" + })); + newSteps.Insert(0, new GitHubActionsUseGnuTarStep()); newSteps.Insert(0, new GitHubActionsConfigureLongPathsStep()); From 7fb36d8914dcacd0523f45c6493978e01d2ac33d Mon Sep 17 00:00:00 2001 From: Cristian Pufu Date: Mon, 2 Oct 2023 09:23:45 +0300 Subject: [PATCH 3/4] Remove unnecessary TargetFramework conditions --- .../AspNetCore/AspNetCoreToOpenApiCommand.cs | 106 ++++++++---------- 1 file changed, 46 insertions(+), 60 deletions(-) diff --git a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs index d27fd5f585..514b3b27cf 100644 --- a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs +++ b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs @@ -95,46 +95,43 @@ public override async Task RunAsync(CommandLineProcessor processor, ICon toolDirectory = Path.GetDirectoryName(typeof(AspNetCoreToOpenApiCommand).GetTypeInfo().Assembly.Location); } - if (projectMetadata.TargetFrameworkIdentifier == ".NETFramework") + string binaryName; + var is32BitProject = string.Equals(projectMetadata.PlatformTarget, "x86", StringComparison.OrdinalIgnoreCase); + if (is32BitProject) { - string binaryName; - var is32BitProject = string.Equals(projectMetadata.PlatformTarget, "x86", StringComparison.OrdinalIgnoreCase); - if (is32BitProject) + if (Environment.Is64BitProcess) { - if (Environment.Is64BitProcess) - { - throw new InvalidOperationException($"The ouput of {projectFile} is a 32-bit application and requires NSwag.Console.x86 to be processed."); - } - - binaryName = LauncherBinaryName + ".x86.exe"; - } - else - { - if (!Environment.Is64BitProcess) - { - throw new InvalidOperationException($"The ouput of {projectFile} is a 64-bit application and requires NSwag.Console to be processed."); - } - - binaryName = LauncherBinaryName + ".exe"; + throw new InvalidOperationException($"The ouput of {projectFile} is a 32-bit application and requires NSwag.Console.x86 to be processed."); } - var executableSource = Path.Combine(toolDirectory, binaryName); - if (!File.Exists(executableSource)) + binaryName = LauncherBinaryName + ".x86.exe"; + } + else + { + if (!Environment.Is64BitProcess) { - throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); + throw new InvalidOperationException($"The ouput of {projectFile} is a 64-bit application and requires NSwag.Console to be processed."); } - executable = Path.Combine(projectMetadata.OutputPath, binaryName); - File.Copy(executableSource, executable, overwrite: true); - cleanupFiles.Add(executable); + binaryName = LauncherBinaryName + ".exe"; + } - var appConfig = Path.Combine(projectMetadata.OutputPath, projectMetadata.TargetFileName + ".config"); - if (File.Exists(appConfig)) - { - var copiedAppConfig = Path.ChangeExtension(executable, ".exe.config"); - File.Copy(appConfig, copiedAppConfig, overwrite: true); - cleanupFiles.Add(copiedAppConfig); - } + var executableSource = Path.Combine(toolDirectory, binaryName); + if (!File.Exists(executableSource)) + { + throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); + } + + executable = Path.Combine(projectMetadata.OutputPath, binaryName); + File.Copy(executableSource, executable, overwrite: true); + cleanupFiles.Add(executable); + + var appConfig = Path.Combine(projectMetadata.OutputPath, projectMetadata.TargetFileName + ".config"); + if (File.Exists(appConfig)) + { + var copiedAppConfig = Path.ChangeExtension(executable, ".exe.config"); + File.Copy(appConfig, copiedAppConfig, overwrite: true); + cleanupFiles.Add(copiedAppConfig); } #else var toolDirectory = AppContext.BaseDirectory; @@ -143,41 +140,30 @@ public override async Task RunAsync(CommandLineProcessor processor, ICon toolDirectory = Path.GetDirectoryName(typeof(AspNetCoreToOpenApiCommand).GetTypeInfo().Assembly.Location); } - if (projectMetadata.TargetFrameworkIdentifier == ".NETCoreApp" || - projectMetadata.TargetFrameworkIdentifier == "net6.0" || - projectMetadata.TargetFrameworkIdentifier == "net7.0" || - projectMetadata.TargetFrameworkIdentifier == "net8.0") - { - executable = "dotnet"; - args.Add("exec"); - args.Add("--depsfile"); - args.Add(projectMetadata.ProjectDepsFilePath); + executable = "dotnet"; + args.Add("exec"); + args.Add("--depsfile"); + args.Add(projectMetadata.ProjectDepsFilePath); - args.Add("--runtimeconfig"); - args.Add(projectMetadata.ProjectRuntimeConfigFilePath); + args.Add("--runtimeconfig"); + args.Add(projectMetadata.ProjectRuntimeConfigFilePath); - var binaryName = LauncherBinaryName + ".dll"; - var executorBinary = Path.Combine(toolDirectory, binaryName); + var binaryName = LauncherBinaryName + ".dll"; + var executorBinary = Path.Combine(toolDirectory, binaryName); - if (!File.Exists(executorBinary)) - { - binaryName = LauncherBinaryName + ".exe"; - executorBinary = Path.Combine(toolDirectory, binaryName); - } - - if (!File.Exists(executorBinary)) - { - throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); - } - - args.Add(executorBinary); + if (!File.Exists(executorBinary)) + { + binaryName = LauncherBinaryName + ".exe"; + executorBinary = Path.Combine(toolDirectory, binaryName); } -#endif - else + + if (!File.Exists(executorBinary)) { - throw new InvalidOperationException($"Unsupported target framework '{projectMetadata.TargetFrameworkIdentifier}'."); + throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); } + args.Add(executorBinary); +#endif var commandFile = Path.GetTempFileName(); var outputFile = Path.GetTempFileName(); File.WriteAllText(commandFile, JsonConvert.SerializeObject(this)); From 21ca965d1fffa41966380eeb4c20d05b4dbe085e Mon Sep 17 00:00:00 2001 From: Rico Suter Date: Mon, 2 Oct 2023 11:46:44 +0200 Subject: [PATCH 4/4] Update AspNetCoreToOpenApiCommand.cs --- .../AspNetCore/AspNetCoreToOpenApiCommand.cs | 106 ++++++++++-------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs index 514b3b27cf..041ffeecb3 100644 --- a/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs +++ b/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs @@ -1,4 +1,4 @@ -//----------------------------------------------------------------------- +//----------------------------------------------------------------------- // // Copyright (c) Rico Suter. All rights reserved. // @@ -95,43 +95,46 @@ public override async Task RunAsync(CommandLineProcessor processor, ICon toolDirectory = Path.GetDirectoryName(typeof(AspNetCoreToOpenApiCommand).GetTypeInfo().Assembly.Location); } - string binaryName; - var is32BitProject = string.Equals(projectMetadata.PlatformTarget, "x86", StringComparison.OrdinalIgnoreCase); - if (is32BitProject) + if (projectMetadata.TargetFrameworkIdentifier == ".NETFramework") { - if (Environment.Is64BitProcess) + string binaryName; + var is32BitProject = string.Equals(projectMetadata.PlatformTarget, "x86", StringComparison.OrdinalIgnoreCase); + if (is32BitProject) { - throw new InvalidOperationException($"The ouput of {projectFile} is a 32-bit application and requires NSwag.Console.x86 to be processed."); - } + if (Environment.Is64BitProcess) + { + throw new InvalidOperationException($"The ouput of {projectFile} is a 32-bit application and requires NSwag.Console.x86 to be processed."); + } - binaryName = LauncherBinaryName + ".x86.exe"; - } - else - { - if (!Environment.Is64BitProcess) - { - throw new InvalidOperationException($"The ouput of {projectFile} is a 64-bit application and requires NSwag.Console to be processed."); + binaryName = LauncherBinaryName + ".x86.exe"; } + else + { + if (!Environment.Is64BitProcess) + { + throw new InvalidOperationException($"The ouput of {projectFile} is a 64-bit application and requires NSwag.Console to be processed."); + } - binaryName = LauncherBinaryName + ".exe"; - } + binaryName = LauncherBinaryName + ".exe"; + } - var executableSource = Path.Combine(toolDirectory, binaryName); - if (!File.Exists(executableSource)) - { - throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); - } + var executableSource = Path.Combine(toolDirectory, binaryName); + if (!File.Exists(executableSource)) + { + throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); + } - executable = Path.Combine(projectMetadata.OutputPath, binaryName); - File.Copy(executableSource, executable, overwrite: true); - cleanupFiles.Add(executable); + executable = Path.Combine(projectMetadata.OutputPath, binaryName); + File.Copy(executableSource, executable, overwrite: true); + cleanupFiles.Add(executable); - var appConfig = Path.Combine(projectMetadata.OutputPath, projectMetadata.TargetFileName + ".config"); - if (File.Exists(appConfig)) - { - var copiedAppConfig = Path.ChangeExtension(executable, ".exe.config"); - File.Copy(appConfig, copiedAppConfig, overwrite: true); - cleanupFiles.Add(copiedAppConfig); + var appConfig = Path.Combine(projectMetadata.OutputPath, projectMetadata.TargetFileName + ".config"); + if (File.Exists(appConfig)) + { + var copiedAppConfig = Path.ChangeExtension(executable, ".exe.config"); + File.Copy(appConfig, copiedAppConfig, overwrite: true); + cleanupFiles.Add(copiedAppConfig); + } } #else var toolDirectory = AppContext.BaseDirectory; @@ -140,30 +143,39 @@ public override async Task RunAsync(CommandLineProcessor processor, ICon toolDirectory = Path.GetDirectoryName(typeof(AspNetCoreToOpenApiCommand).GetTypeInfo().Assembly.Location); } - executable = "dotnet"; - args.Add("exec"); - args.Add("--depsfile"); - args.Add(projectMetadata.ProjectDepsFilePath); + if (projectMetadata.TargetFrameworkIdentifier == ".NETCoreApp" || + projectMetadata.TargetFrameworkIdentifier.StartsWith("net")) + { + executable = "dotnet"; + args.Add("exec"); + args.Add("--depsfile"); + args.Add(projectMetadata.ProjectDepsFilePath); - args.Add("--runtimeconfig"); - args.Add(projectMetadata.ProjectRuntimeConfigFilePath); + args.Add("--runtimeconfig"); + args.Add(projectMetadata.ProjectRuntimeConfigFilePath); - var binaryName = LauncherBinaryName + ".dll"; - var executorBinary = Path.Combine(toolDirectory, binaryName); + var binaryName = LauncherBinaryName + ".dll"; + var executorBinary = Path.Combine(toolDirectory, binaryName); - if (!File.Exists(executorBinary)) - { - binaryName = LauncherBinaryName + ".exe"; - executorBinary = Path.Combine(toolDirectory, binaryName); - } + if (!File.Exists(executorBinary)) + { + binaryName = LauncherBinaryName + ".exe"; + executorBinary = Path.Combine(toolDirectory, binaryName); + } + + if (!File.Exists(executorBinary)) + { + throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); + } - if (!File.Exists(executorBinary)) + args.Add(executorBinary); + } +#endif + else { - throw new InvalidOperationException($"Unable to locate {binaryName} in {toolDirectory}."); + throw new InvalidOperationException($"Unsupported target framework '{projectMetadata.TargetFrameworkIdentifier}'."); } - args.Add(executorBinary); -#endif var commandFile = Path.GetTempFileName(); var outputFile = Path.GetTempFileName(); File.WriteAllText(commandFile, JsonConvert.SerializeObject(this));