From 12c4a961b09d746b44aa49a82529830fae5a59d4 Mon Sep 17 00:00:00 2001 From: remcolam Date: Thu, 25 Apr 2024 11:09:13 +0200 Subject: [PATCH] Add customized document serialization support (#2677) Added new `ISwaggerDocumentSerializer` interface for custom serialization support. --- Swashbuckle.AspNetCore.sln | 277 +----------------- src/Swashbuckle.AspNetCore.Cli/Program.cs | 35 ++- .../SwaggerOptionsExtensions.cs | 29 ++ .../SwaggerServiceCollectionExtensions.cs | 22 ++ .../ISwaggerDocumentSerializer.cs | 20 ++ .../SwaggerMiddleware.cs | 34 ++- .../SwaggerOptions.cs | 8 +- .../DependencyInjection/DocumentProvider.cs | 14 +- .../DependencyInjection/SwaggerGenOptions.cs | 2 +- .../Swashbuckle.AspNetCore.Cli.Test.csproj | 2 + .../ToolTests.cs | 82 +++--- .../CustomDocumentSerializerTests.cs | 104 +++++++ ...hbuckle.AspNetCore.IntegrationTests.csproj | 1 + .../Utilities/TemporaryDirectory.cs | 25 ++ .../Controllers/WeatherForecastController.cs | 32 ++ .../CustomDocumentSerializer.csproj | 17 ++ .../DocumentSerializerTest.cs | 26 ++ .../CustomDocumentSerializer/Program.cs | 17 ++ .../Properties/launchSettings.json | 31 ++ .../CustomDocumentSerializer/Startup.cs | 41 +++ .../WeatherForecast.cs | 12 + .../appsettings.Development.json | 8 + .../CustomDocumentSerializer/appsettings.json | 9 + test/WebSites/NswagClientExample/swagger.json | 40 +-- 24 files changed, 552 insertions(+), 336 deletions(-) create mode 100644 src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerOptionsExtensions.cs create mode 100644 src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerServiceCollectionExtensions.cs create mode 100644 src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs create mode 100644 test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs create mode 100644 test/Swashbuckle.AspNetCore.TestSupport/Utilities/TemporaryDirectory.cs create mode 100644 test/WebSites/CustomDocumentSerializer/Controllers/WeatherForecastController.cs create mode 100644 test/WebSites/CustomDocumentSerializer/CustomDocumentSerializer.csproj create mode 100644 test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs create mode 100644 test/WebSites/CustomDocumentSerializer/Program.cs create mode 100644 test/WebSites/CustomDocumentSerializer/Properties/launchSettings.json create mode 100644 test/WebSites/CustomDocumentSerializer/Startup.cs create mode 100644 test/WebSites/CustomDocumentSerializer/WeatherForecast.cs create mode 100644 test/WebSites/CustomDocumentSerializer/appsettings.Development.json create mode 100644 test/WebSites/CustomDocumentSerializer/appsettings.json diff --git a/Swashbuckle.AspNetCore.sln b/Swashbuckle.AspNetCore.sln index 0179a8b1c5..f394ca4df6 100644 --- a/Swashbuckle.AspNetCore.sln +++ b/Swashbuckle.AspNetCore.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31717.71 @@ -109,412 +109,150 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\update-dotnet-sdk.yml = .github\workflows\update-dotnet-sdk.yml EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomDocumentSerializer", "test\WebSites\CustomDocumentSerializer\CustomDocumentSerializer.csproj", "{B6037A37-4A4F-438D-B18A-0C9D1408EAB2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|x64.ActiveCfg = Debug|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|x64.Build.0 = Debug|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|x86.ActiveCfg = Debug|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Debug|x86.Build.0 = Debug|Any CPU {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|Any CPU.ActiveCfg = Release|Any CPU {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|Any CPU.Build.0 = Release|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|x64.ActiveCfg = Release|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|x64.Build.0 = Release|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|x86.ActiveCfg = Release|Any CPU - {60EF9E95-84D6-44CE-968D-50237424CB16}.Release|x86.Build.0 = Release|Any CPU {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|x64.ActiveCfg = Debug|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|x64.Build.0 = Debug|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|x86.ActiveCfg = Debug|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Debug|x86.Build.0 = Debug|Any CPU {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|Any CPU.Build.0 = Release|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|x64.ActiveCfg = Release|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|x64.Build.0 = Release|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|x86.ActiveCfg = Release|Any CPU - {4AC6DB4A-CBA2-493D-88F8-82D631B9DA7B}.Release|x86.Build.0 = Release|Any CPU {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|x64.ActiveCfg = Debug|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|x64.Build.0 = Debug|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|x86.ActiveCfg = Debug|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Debug|x86.Build.0 = Debug|Any CPU {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|Any CPU.Build.0 = Release|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|x64.ActiveCfg = Release|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|x64.Build.0 = Release|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|x86.ActiveCfg = Release|Any CPU - {7D077710-1B4A-4DEC-96E9-CE6192D4493D}.Release|x86.Build.0 = Release|Any CPU {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|x64.ActiveCfg = Debug|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|x64.Build.0 = Debug|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|x86.ActiveCfg = Debug|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Debug|x86.Build.0 = Debug|Any CPU {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|Any CPU.Build.0 = Release|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|x64.ActiveCfg = Release|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|x64.Build.0 = Release|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|x86.ActiveCfg = Release|Any CPU - {B5E94C7D-B76E-4181-87E5-ACD8971A987E}.Release|x86.Build.0 = Release|Any CPU {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|x64.ActiveCfg = Debug|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|x64.Build.0 = Debug|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|x86.ActiveCfg = Debug|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Debug|x86.Build.0 = Debug|Any CPU {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|Any CPU.ActiveCfg = Release|Any CPU {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|Any CPU.Build.0 = Release|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|x64.ActiveCfg = Release|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|x64.Build.0 = Release|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|x86.ActiveCfg = Release|Any CPU - {3164424E-D74A-45CD-BE17-BE33ED79C090}.Release|x86.Build.0 = Release|Any CPU {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|x64.ActiveCfg = Debug|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|x64.Build.0 = Debug|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|x86.ActiveCfg = Debug|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Debug|x86.Build.0 = Debug|Any CPU {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|Any CPU.Build.0 = Release|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|x64.ActiveCfg = Release|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|x64.Build.0 = Release|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|x86.ActiveCfg = Release|Any CPU - {3A64AC4B-E68A-4FAF-AA47-2C41DF090DEF}.Release|x86.Build.0 = Release|Any CPU {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|x64.ActiveCfg = Debug|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|x64.Build.0 = Debug|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|x86.ActiveCfg = Debug|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Debug|x86.Build.0 = Debug|Any CPU {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|Any CPU.Build.0 = Release|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|x64.ActiveCfg = Release|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|x64.Build.0 = Release|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|x86.ActiveCfg = Release|Any CPU - {E77079C1-51C1-47F1-A841-B4BF040EFFA0}.Release|x86.Build.0 = Release|Any CPU {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|x64.ActiveCfg = Debug|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|x64.Build.0 = Debug|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|x86.ActiveCfg = Debug|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Debug|x86.Build.0 = Debug|Any CPU {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|Any CPU.ActiveCfg = Release|Any CPU {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|Any CPU.Build.0 = Release|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|x64.ActiveCfg = Release|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|x64.Build.0 = Release|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|x86.ActiveCfg = Release|Any CPU - {756A46AA-E577-4500-9FBA-D3D406811DB5}.Release|x86.Build.0 = Release|Any CPU {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|x64.ActiveCfg = Debug|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|x64.Build.0 = Debug|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|x86.ActiveCfg = Debug|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Debug|x86.Build.0 = Debug|Any CPU {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|Any CPU.ActiveCfg = Release|Any CPU {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|Any CPU.Build.0 = Release|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|x64.ActiveCfg = Release|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|x64.Build.0 = Release|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|x86.ActiveCfg = Release|Any CPU - {0783E72E-3483-43AF-AE4B-2A6CFAFD3DD3}.Release|x86.Build.0 = Release|Any CPU {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|x64.ActiveCfg = Debug|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|x64.Build.0 = Debug|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|x86.ActiveCfg = Debug|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Debug|x86.Build.0 = Debug|Any CPU {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|Any CPU.Build.0 = Release|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|x64.ActiveCfg = Release|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|x64.Build.0 = Release|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|x86.ActiveCfg = Release|Any CPU - {7F045714-B571-45A4-A75E-D3B8386D4E33}.Release|x86.Build.0 = Release|Any CPU {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|Any CPU.Build.0 = Debug|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|x64.ActiveCfg = Debug|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|x64.Build.0 = Debug|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|x86.ActiveCfg = Debug|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Debug|x86.Build.0 = Debug|Any CPU {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|Any CPU.ActiveCfg = Release|Any CPU {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|Any CPU.Build.0 = Release|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|x64.ActiveCfg = Release|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|x64.Build.0 = Release|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|x86.ActiveCfg = Release|Any CPU - {569A93BE-931F-41F1-8D74-B1CF1399B580}.Release|x86.Build.0 = Release|Any CPU {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|x64.ActiveCfg = Debug|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|x64.Build.0 = Debug|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|x86.ActiveCfg = Debug|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Debug|x86.Build.0 = Debug|Any CPU {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|Any CPU.ActiveCfg = Release|Any CPU {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|Any CPU.Build.0 = Release|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|x64.ActiveCfg = Release|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|x64.Build.0 = Release|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|x86.ActiveCfg = Release|Any CPU - {3DDA9029-8FF9-4477-8B14-473D741C125E}.Release|x86.Build.0 = Release|Any CPU {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|x64.ActiveCfg = Debug|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|x64.Build.0 = Debug|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|x86.ActiveCfg = Debug|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Debug|x86.Build.0 = Debug|Any CPU {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|Any CPU.Build.0 = Release|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|x64.ActiveCfg = Release|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|x64.Build.0 = Release|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|x86.ActiveCfg = Release|Any CPU - {B0FE6E3D-21A6-4873-843B-C6B08AAC214A}.Release|x86.Build.0 = Release|Any CPU {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|x64.ActiveCfg = Debug|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|x64.Build.0 = Debug|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|x86.ActiveCfg = Debug|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Debug|x86.Build.0 = Debug|Any CPU {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|Any CPU.ActiveCfg = Release|Any CPU {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|Any CPU.Build.0 = Release|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|x64.ActiveCfg = Release|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|x64.Build.0 = Release|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|x86.ActiveCfg = Release|Any CPU - {29E029D8-903F-447F-B15A-EA406AD5A743}.Release|x86.Build.0 = Release|Any CPU {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|x64.ActiveCfg = Debug|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|x64.Build.0 = Debug|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|x86.ActiveCfg = Debug|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Debug|x86.Build.0 = Debug|Any CPU {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|Any CPU.Build.0 = Release|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|x64.ActiveCfg = Release|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|x64.Build.0 = Release|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|x86.ActiveCfg = Release|Any CPU - {F3318D97-60E4-45F1-9DD8-007323C06CB8}.Release|x86.Build.0 = Release|Any CPU {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|x64.ActiveCfg = Debug|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|x64.Build.0 = Debug|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|x86.ActiveCfg = Debug|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Debug|x86.Build.0 = Debug|Any CPU {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|Any CPU.Build.0 = Release|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|x64.ActiveCfg = Release|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|x64.Build.0 = Release|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|x86.ActiveCfg = Release|Any CPU - {C6F447A4-ED99-4932-AC29-950BD794D0B3}.Release|x86.Build.0 = Release|Any CPU {62B46064-24F0-417A-8EA0-34684720A379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62B46064-24F0-417A-8EA0-34684720A379}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Debug|x64.ActiveCfg = Debug|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Debug|x64.Build.0 = Debug|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Debug|x86.ActiveCfg = Debug|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Debug|x86.Build.0 = Debug|Any CPU {62B46064-24F0-417A-8EA0-34684720A379}.Release|Any CPU.ActiveCfg = Release|Any CPU {62B46064-24F0-417A-8EA0-34684720A379}.Release|Any CPU.Build.0 = Release|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Release|x64.ActiveCfg = Release|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Release|x64.Build.0 = Release|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Release|x86.ActiveCfg = Release|Any CPU - {62B46064-24F0-417A-8EA0-34684720A379}.Release|x86.Build.0 = Release|Any CPU {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|x64.ActiveCfg = Debug|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|x64.Build.0 = Debug|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|x86.ActiveCfg = Debug|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Debug|x86.Build.0 = Debug|Any CPU {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|Any CPU.ActiveCfg = Release|Any CPU {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|Any CPU.Build.0 = Release|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|x64.ActiveCfg = Release|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|x64.Build.0 = Release|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|x86.ActiveCfg = Release|Any CPU - {1D31109C-377C-40C7-9A06-DB078FC24578}.Release|x86.Build.0 = Release|Any CPU {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|x64.ActiveCfg = Debug|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|x64.Build.0 = Debug|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|x86.ActiveCfg = Debug|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Debug|x86.Build.0 = Debug|Any CPU {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|Any CPU.ActiveCfg = Release|Any CPU {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|Any CPU.Build.0 = Release|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|x64.ActiveCfg = Release|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|x64.Build.0 = Release|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|x86.ActiveCfg = Release|Any CPU - {E46D07EE-5EA6-4630-8FD2-B2150F35D33A}.Release|x86.Build.0 = Release|Any CPU {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|x64.ActiveCfg = Debug|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|x64.Build.0 = Debug|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|x86.ActiveCfg = Debug|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Debug|x86.Build.0 = Debug|Any CPU {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|Any CPU.Build.0 = Release|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|x64.ActiveCfg = Release|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|x64.Build.0 = Release|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|x86.ActiveCfg = Release|Any CPU - {8CA201CD-7F59-4B7D-8888-76528F2DF3C8}.Release|x86.Build.0 = Release|Any CPU {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|x64.ActiveCfg = Debug|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|x64.Build.0 = Debug|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|x86.ActiveCfg = Debug|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Debug|x86.Build.0 = Debug|Any CPU {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|Any CPU.Build.0 = Release|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|x64.ActiveCfg = Release|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|x64.Build.0 = Release|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|x86.ActiveCfg = Release|Any CPU - {0DA4F00E-D365-4D27-B8C4-F6D4577F2093}.Release|x86.Build.0 = Release|Any CPU {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|x64.ActiveCfg = Debug|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|x64.Build.0 = Debug|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|x86.ActiveCfg = Debug|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Debug|x86.Build.0 = Debug|Any CPU {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|Any CPU.ActiveCfg = Release|Any CPU {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|Any CPU.Build.0 = Release|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|x64.ActiveCfg = Release|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|x64.Build.0 = Release|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|x86.ActiveCfg = Release|Any CPU - {48634D50-2680-4103-8CDA-8B6D99291AC5}.Release|x86.Build.0 = Release|Any CPU {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|x64.ActiveCfg = Debug|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|x64.Build.0 = Debug|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|x86.ActiveCfg = Debug|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Debug|x86.Build.0 = Debug|Any CPU {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|Any CPU.ActiveCfg = Release|Any CPU {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|Any CPU.Build.0 = Release|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|x64.ActiveCfg = Release|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|x64.Build.0 = Release|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|x86.ActiveCfg = Release|Any CPU - {12430BE8-FEB2-49E1-A944-687744DC3203}.Release|x86.Build.0 = Release|Any CPU {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|x64.ActiveCfg = Debug|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|x64.Build.0 = Debug|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|x86.ActiveCfg = Debug|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Debug|x86.Build.0 = Debug|Any CPU {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|Any CPU.ActiveCfg = Release|Any CPU {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|Any CPU.Build.0 = Release|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|x64.ActiveCfg = Release|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|x64.Build.0 = Release|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|x86.ActiveCfg = Release|Any CPU - {E59CDCA2-8C49-4D73-ACB1-BB4B0D03BC81}.Release|x86.Build.0 = Release|Any CPU {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|x64.ActiveCfg = Debug|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|x64.Build.0 = Debug|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|x86.ActiveCfg = Debug|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Debug|x86.Build.0 = Debug|Any CPU {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|Any CPU.Build.0 = Release|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|x64.ActiveCfg = Release|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|x64.Build.0 = Release|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|x86.ActiveCfg = Release|Any CPU - {C856B095-5AD2-4068-AE51-2C9457B840A3}.Release|x86.Build.0 = Release|Any CPU {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|x64.ActiveCfg = Debug|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|x64.Build.0 = Debug|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|x86.ActiveCfg = Debug|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Debug|x86.Build.0 = Debug|Any CPU {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|Any CPU.Build.0 = Release|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|x64.ActiveCfg = Release|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|x64.Build.0 = Release|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|x86.ActiveCfg = Release|Any CPU - {CB95026D-03AC-4D19-B768-1C83F03B4F09}.Release|x86.Build.0 = Release|Any CPU {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|x64.ActiveCfg = Debug|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|x64.Build.0 = Debug|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|x86.ActiveCfg = Debug|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Debug|x86.Build.0 = Debug|Any CPU {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|Any CPU.ActiveCfg = Release|Any CPU {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|Any CPU.Build.0 = Release|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|x64.ActiveCfg = Release|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|x64.Build.0 = Release|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|x86.ActiveCfg = Release|Any CPU - {53E3C3CF-54D6-41C0-A14E-57F0E792768A}.Release|x86.Build.0 = Release|Any CPU {35075180-DC95-4689-9059-01B83B61495C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35075180-DC95-4689-9059-01B83B61495C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Debug|x64.ActiveCfg = Debug|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Debug|x64.Build.0 = Debug|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Debug|x86.ActiveCfg = Debug|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Debug|x86.Build.0 = Debug|Any CPU {35075180-DC95-4689-9059-01B83B61495C}.Release|Any CPU.ActiveCfg = Release|Any CPU {35075180-DC95-4689-9059-01B83B61495C}.Release|Any CPU.Build.0 = Release|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Release|x64.ActiveCfg = Release|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Release|x64.Build.0 = Release|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Release|x86.ActiveCfg = Release|Any CPU - {35075180-DC95-4689-9059-01B83B61495C}.Release|x86.Build.0 = Release|Any CPU {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|Any CPU.Build.0 = Debug|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|x64.ActiveCfg = Debug|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|x64.Build.0 = Debug|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|x86.ActiveCfg = Debug|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Debug|x86.Build.0 = Debug|Any CPU {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|Any CPU.ActiveCfg = Release|Any CPU {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|Any CPU.Build.0 = Release|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|x64.ActiveCfg = Release|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|x64.Build.0 = Release|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|x86.ActiveCfg = Release|Any CPU - {820BB929-97CF-441D-B7E3-507DF4B15D09}.Release|x86.Build.0 = Release|Any CPU {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|Any CPU.Build.0 = Debug|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|x64.ActiveCfg = Debug|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|x64.Build.0 = Debug|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|x86.ActiveCfg = Debug|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Debug|x86.Build.0 = Debug|Any CPU {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|Any CPU.ActiveCfg = Release|Any CPU {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|Any CPU.Build.0 = Release|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|x64.ActiveCfg = Release|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|x64.Build.0 = Release|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|x86.ActiveCfg = Release|Any CPU - {76692D68-C38C-4A7D-B3DA-DA78A393E266}.Release|x86.Build.0 = Release|Any CPU {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|x64.ActiveCfg = Debug|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|x64.Build.0 = Debug|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|x86.ActiveCfg = Debug|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Debug|x86.Build.0 = Debug|Any CPU {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|Any CPU.Build.0 = Release|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|x64.ActiveCfg = Release|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|x64.Build.0 = Release|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|x86.ActiveCfg = Release|Any CPU - {66590FBA-5FDD-4AC9-AF91-26ADAB33CCB8}.Release|x86.Build.0 = Release|Any CPU {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|x64.ActiveCfg = Debug|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|x64.Build.0 = Debug|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|x86.ActiveCfg = Debug|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Debug|x86.Build.0 = Debug|Any CPU {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|Any CPU.Build.0 = Release|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|x64.ActiveCfg = Release|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|x64.Build.0 = Release|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|x86.ActiveCfg = Release|Any CPU - {3D0126CB-5439-483C-B2D5-4B4BE111D15C}.Release|x86.Build.0 = Release|Any CPU + {B6037A37-4A4F-438D-B18A-0C9D1408EAB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6037A37-4A4F-438D-B18A-0C9D1408EAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6037A37-4A4F-438D-B18A-0C9D1408EAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6037A37-4A4F-438D-B18A-0C9D1408EAB2}.Release|Any CPU.Build.0 = Release|Any CPU {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|x64.ActiveCfg = Debug|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|x64.Build.0 = Debug|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|x86.ActiveCfg = Debug|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Debug|x86.Build.0 = Debug|Any CPU {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|Any CPU.Build.0 = Release|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|x64.ActiveCfg = Release|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|x64.Build.0 = Release|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|x86.ActiveCfg = Release|Any CPU - {6EA75DA8-9B1F-468E-9425-37F01A129B0F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -556,6 +294,7 @@ Global {6EA75DA8-9B1F-468E-9425-37F01A129B0F} = {DB3F57FC-1472-4F03-B551-43394DA3C5EB} {3BA087DA-788C-43D6-9D8B-1EF017014A4A} = {FA1B4021-0A97-4F68-B966-148191F6AAA8} {A0EC16BE-C520-4FCF-BB54-2D79CD255F00} = {3BA087DA-788C-43D6-9D8B-1EF017014A4A} + {B6037A37-4A4F-438D-B18A-0C9D1408EAB2} = {DB3F57FC-1472-4F03-B551-43394DA3C5EB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {36FC6A67-247D-4149-8EDD-79FFD1A75F51} diff --git a/src/Swashbuckle.AspNetCore.Cli/Program.cs b/src/Swashbuckle.AspNetCore.Cli/Program.cs index 62b4dd162a..7b9de83524 100644 --- a/src/Swashbuckle.AspNetCore.Cli/Program.cs +++ b/src/Swashbuckle.AspNetCore.Cli/Program.cs @@ -1,15 +1,18 @@ using System; -using System.Reflection; using System.Diagnostics; +using System.Globalization; using System.IO; -using System.Runtime.Loader; using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Threading; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Microsoft.OpenApi.Writers; using Swashbuckle.AspNetCore.Swagger; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore; -using Microsoft.Extensions.Hosting; namespace Swashbuckle.AspNetCore.Cli { @@ -87,6 +90,8 @@ public static int Main(string[] args) // 3) Retrieve Swagger via configured provider var swaggerProvider = serviceProvider.GetRequiredService(); + var swaggerOptions = serviceProvider.GetService>(); + var swaggerDocumentSerializer = swaggerOptions?.Value?.CustomDocumentSerializer; var swagger = swaggerProvider.GetSwagger( namedArgs["swaggerdoc"], namedArgs.TryGetValue("--host", out var arg) ? arg : null, @@ -97,7 +102,8 @@ public static int Main(string[] args) ? Path.Combine(Directory.GetCurrentDirectory(), arg1) : null; - using (var streamWriter = (outputPath != null ? File.CreateText(outputPath) : Console.Out)) + using (Stream stream = (outputPath != null ? File.OpenWrite(outputPath) : Console.OpenStandardOutput())) + using (var streamWriter = new FormattingStreamWriter(stream, CultureInfo.InvariantCulture)) { IOpenApiWriter writer; if (namedArgs.ContainsKey("--yaml")) @@ -106,9 +112,24 @@ public static int Main(string[] args) writer = new OpenApiJsonWriter(streamWriter); if (namedArgs.ContainsKey("--serializeasv2")) - swagger.SerializeAsV2(writer); + { + if (swaggerDocumentSerializer != null) + { + swaggerDocumentSerializer.SerializeDocument(swagger, writer, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0); + } + else + { + swagger.SerializeAsV2(writer); + } + } + else if (swaggerDocumentSerializer != null) + { + swaggerDocumentSerializer.SerializeDocument(swagger, writer, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0); + } else + { swagger.SerializeAsV3(writer); + } if (outputPath != null) Console.WriteLine($"Swagger JSON/YAML successfully written to {outputPath}"); diff --git a/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerOptionsExtensions.cs b/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerOptionsExtensions.cs new file mode 100644 index 0000000000..7decc59331 --- /dev/null +++ b/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerOptionsExtensions.cs @@ -0,0 +1,29 @@ +using System; +using Swashbuckle.AspNetCore.Swagger; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extensions for helping with configuring instances of . +/// +public static class SwaggerOptionsExtensions +{ + /// + /// Sets a custom Swagger document serializer to use. + /// + /// For the CLI tool to be able to use this, this needs to be configured for use in the service collection of your application. + /// The type of the custom Swagger document serializer implementation. + /// The options to configure the serializer for. + /// The parameters to pass into the constructor of the custom Swagger document serializer implementation. + public static void SetCustomDocumentSerializer( + this SwaggerOptions swaggerOptions, + params object[] constructorParameters) + where TDocumentSerializer : ISwaggerDocumentSerializer + { + if (swaggerOptions == null) + { + throw new ArgumentNullException(nameof(swaggerOptions)); + } + swaggerOptions.CustomDocumentSerializer = (TDocumentSerializer)Activator.CreateInstance(typeof(TDocumentSerializer), constructorParameters); + } +} diff --git a/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerServiceCollectionExtensions.cs b/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerServiceCollectionExtensions.cs new file mode 100644 index 0000000000..b64f04afd9 --- /dev/null +++ b/src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerServiceCollectionExtensions.cs @@ -0,0 +1,22 @@ +using System; +using Swashbuckle.AspNetCore.Swagger; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extensions to configure dependencies for Swagger. +/// +public static class SwaggerServiceCollectionExtensions +{ + /// + /// Configures Swagger options in the specified service collection. + /// + /// The service collection to configure the Swagger options for. + /// A delegate to a method to use to configure the Swagger options. + public static void ConfigureSwagger( + this IServiceCollection services, + Action setupAction) + { + services.Configure(setupAction); + } +} diff --git a/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs new file mode 100644 index 0000000000..1601b8b656 --- /dev/null +++ b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs @@ -0,0 +1,20 @@ +using Microsoft.OpenApi; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Writers; + +namespace Swashbuckle.AspNetCore.Swagger +{ + /// + /// Provide an implementation for this interface if you wish to customize how the OpenAPI document is written. + /// + public interface ISwaggerDocumentSerializer + { + /// + /// Serializes an OpenAPI document. + /// + /// The OpenAPI document that should be serialized. + /// The writer to which the document needs to be written. + /// The OpenAPI specification version to serialize as. + void SerializeDocument(OpenApiDocument document, IOpenApiWriter writer, OpenApiSpecVersion specVersion); + } +} diff --git a/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs b/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs index e94802806e..0ef11d7559 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using System.IO; using System.Text; using System.Threading.Tasks; @@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Routing.Patterns; #endif using Microsoft.AspNetCore.Routing.Template; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; @@ -134,7 +136,20 @@ private async Task RespondWithSwaggerJson(HttpResponse response, OpenApiDocument using (var textWriter = new StringWriter(CultureInfo.InvariantCulture)) { var jsonWriter = new OpenApiJsonWriter(textWriter); - if (_options.SerializeAsV2) swagger.SerializeAsV2(jsonWriter); else swagger.SerializeAsV3(jsonWriter); + if (_options.SerializeAsV2) + { + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, jsonWriter, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0); + else + swagger.SerializeAsV2(jsonWriter); + } + else + { + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, jsonWriter, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0); + else + swagger.SerializeAsV3(jsonWriter); + } await response.WriteAsync(textWriter.ToString(), new UTF8Encoding(false)); } @@ -148,7 +163,20 @@ private async Task RespondWithSwaggerYaml(HttpResponse response, OpenApiDocument using (var textWriter = new StringWriter(CultureInfo.InvariantCulture)) { var yamlWriter = new OpenApiYamlWriter(textWriter); - if (_options.SerializeAsV2) swagger.SerializeAsV2(yamlWriter); else swagger.SerializeAsV3(yamlWriter); + if (_options.SerializeAsV2) + { + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, yamlWriter, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0); + else + swagger.SerializeAsV2(yamlWriter); + } + else + { + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, yamlWriter, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0); + else + swagger.SerializeAsV3(yamlWriter); + } await response.WriteAsync(textWriter.ToString(), new UTF8Encoding(false)); } diff --git a/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs b/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs index 4cb89816f4..bc5fcd1516 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs @@ -25,9 +25,15 @@ public SwaggerOptions() /// public bool SerializeAsV2 { get; set; } + /// + /// Gets or sets an optional custom implementation to use to serialize Swagger documents. + /// + /// For the CLI tool to be able to use this, this needs to be configured for use in the service collection of your application. + public ISwaggerDocumentSerializer CustomDocumentSerializer { get; set; } + /// /// Actions that can be applied to an OpenApiDocument before it's serialized. - /// Useful for setting metadata that's derived from the current request + /// Useful for setting metadata that's derived from the current request. /// public List> PreSerializeFilters { get; private set; } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs index a2b342fbb2..401eabba6d 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Writers; using Swashbuckle.AspNetCore.Swagger; @@ -47,11 +49,17 @@ public async Task GenerateAsync(string documentName, TextWriter writer) var jsonWriter = new OpenApiJsonWriter(writer); if (_options.SerializeAsV2) { - swagger.SerializeAsV2(jsonWriter); + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, jsonWriter, OpenApi.OpenApiSpecVersion.OpenApi2_0); + else + swagger.SerializeAsV2(jsonWriter); } else { - swagger.SerializeAsV3(jsonWriter); + if (_options.CustomDocumentSerializer != null) + _options.CustomDocumentSerializer.SerializeDocument(swagger, jsonWriter, OpenApi.OpenApiSpecVersion.OpenApi3_0); + else + swagger.SerializeAsV3(jsonWriter); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs index b6789bea78..af02a9201d 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs @@ -31,4 +31,4 @@ public class FilterDescriptor public object[] Arguments { get; set; } } -} \ No newline at end of file +} diff --git a/test/Swashbuckle.AspNetCore.Cli.Test/Swashbuckle.AspNetCore.Cli.Test.csproj b/test/Swashbuckle.AspNetCore.Cli.Test/Swashbuckle.AspNetCore.Cli.Test.csproj index da3d75f117..bf44a6436a 100644 --- a/test/Swashbuckle.AspNetCore.Cli.Test/Swashbuckle.AspNetCore.Cli.Test.csproj +++ b/test/Swashbuckle.AspNetCore.Cli.Test/Swashbuckle.AspNetCore.Cli.Test.csproj @@ -5,7 +5,9 @@ + + diff --git a/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs b/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs index ae6b54df25..f71213ebca 100644 --- a/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs +++ b/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Text.Json; +using Swashbuckle.AspNetCore.TestSupport.Utilities; using Xunit; namespace Swashbuckle.AspNetCore.Cli.Test @@ -16,46 +17,59 @@ public void Throws_When_Startup_Assembly_Does_Not_Exist() [Fact] public void Can_Generate_Swagger_Json() { - var dir = Directory.CreateDirectory(Path.Join(Path.GetTempPath(), Path.GetRandomFileName())); - try - { - var args = new string[] { "tofile", "--output", $"{dir}/swagger.json", "--serializeasv2", Path.Combine(Directory.GetCurrentDirectory(), "Basic.dll"), "v1" }; - Assert.Equal(0, Program.Main(args)); - - using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(dir.FullName, "swagger.json"))); - - // verify one of the endpoints - var paths = document.RootElement.GetProperty("paths"); - var productsPath = paths.GetProperty("/products"); - Assert.True(productsPath.TryGetProperty("post", out _)); - } - finally - { - dir.Delete(true); - } + using var temporaryDirectory = new TemporaryDirectory(); + var args = new string[] { "tofile", "--output", $"{temporaryDirectory.Path}/swagger.json", "--serializeasv2", Path.Combine(Directory.GetCurrentDirectory(), "Basic.dll"), "v1" }; + Assert.Equal(0, Program.Main(args)); + using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(temporaryDirectory.Path, "swagger.json"))); + + // verify one of the endpoints + var paths = document.RootElement.GetProperty("paths"); + var productsPath = paths.GetProperty("/products"); + Assert.True(productsPath.TryGetProperty("post", out _)); + } + + [Fact] + public void CustomDocumentSerializer_Writes_Custom_V2_Document() + { + using var temporaryDirectory = new TemporaryDirectory(); + var args = new string[] { "tofile", "--output", $"{temporaryDirectory.Path}/swagger.json", "--serializeasv2", Path.Combine(Directory.GetCurrentDirectory(), "CustomDocumentSerializer.dll"), "v1" }; + Assert.Equal(0, Program.Main(args)); + + using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(temporaryDirectory.Path, "swagger.json"))); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest2.0", swaggerInfo); + } + + [Fact] + public void CustomDocumentSerializer_Writes_Custom_V3_Document() + { + using var temporaryDirectory = new TemporaryDirectory(); + var args = new string[] { "tofile", "--output", $"{temporaryDirectory.Path}/swagger.json", Path.Combine(Directory.GetCurrentDirectory(), "CustomDocumentSerializer.dll"), "v1" }; + Assert.Equal(0, Program.Main(args)); + + using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(temporaryDirectory.Path, "swagger.json"))); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.0", swaggerInfo); } #if NET6_0_OR_GREATER [Fact] public void Can_Generate_Swagger_Json_ForTopLevelApp() { - var dir = Directory.CreateDirectory(Path.Join(Path.GetTempPath(), Path.GetRandomFileName())); - try - { - var args = new string[] { "tofile", "--output", $"{dir}/swagger.json", "--serializeasv2", Path.Combine(Directory.GetCurrentDirectory(), "MinimalApp.dll"), "v1" }; - Assert.Equal(0, Program.Main(args)); - - using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(dir.FullName, "swagger.json"))); - - // verify one of the endpoints - var paths = document.RootElement.GetProperty("paths"); - var path = paths.GetProperty("/WeatherForecast"); - Assert.True(path.TryGetProperty("get", out _)); - } - finally - { - dir.Delete(true); - } + using var temporaryDirectory = new TemporaryDirectory(); + var args = new string[] { "tofile", "--output", $"{temporaryDirectory.Path}/swagger.json", "--serializeasv2", Path.Combine(Directory.GetCurrentDirectory(), "MinimalApp.dll"), "v1" }; + Assert.Equal(0, Program.Main(args)); + + using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(temporaryDirectory.Path, "swagger.json"))); + + // verify one of the endpoints + var paths = document.RootElement.GetProperty("paths"); + var path = paths.GetProperty("/WeatherForecast"); + Assert.True(path.TryGetProperty("get", out _)); } #endif } diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs new file mode 100644 index 0000000000..8ce33c6966 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs @@ -0,0 +1,104 @@ +using System.IO; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.ApiDescriptions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Swashbuckle.AspNetCore.Swagger; +using Xunit; + +namespace Swashbuckle.AspNetCore.IntegrationTests +{ + public class CustomDocumentSerializerTests + { + [Fact] + public async void TestSite_Writes_Custom_V3_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup)); + var client = testSite.BuildClient(); + + var swaggerResponse = await client.GetAsync($"/swagger/v1/swagger.json"); + + swaggerResponse.EnsureSuccessStatusCode(); + var contentStream = await swaggerResponse.Content.ReadAsStreamAsync(); + using var document = JsonDocument.Parse(contentStream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.0", swaggerInfo); + } + + [Fact] + public async void TestSite_Writes_Custom_V2_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup)); + var client = testSite.BuildClient(); + + var swaggerResponse = await client.GetAsync($"/swagger/v1/swaggerv2.json"); + + swaggerResponse.EnsureSuccessStatusCode(); + var contentStream = await swaggerResponse.Content.ReadAsStreamAsync(); + using var document = JsonDocument.Parse(contentStream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest2.0", swaggerInfo); + } + + [Fact] + public async Task DocumentProvider_Writes_Custom_V3_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup)); + var server = testSite.BuildServer(); + var services = server.Host.Services; + + var documentProvider = services.GetService(); + using (var stream = new MemoryStream()) + { + using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 2048, leaveOpen: true)) + { + await documentProvider.GenerateAsync("v1", writer); + await writer.FlushAsync(); + } + + stream.Position = 0L; + + using var document = JsonDocument.Parse(stream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.0", swaggerInfo); + } + } + + [Fact] + public async Task DocumentProvider_Writes_Custom_V2_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup)); + var server = testSite.BuildServer(); + var services = server.Host.Services; + + var documentProvider = services.GetService(); + var options = services.GetService>(); + options.Value.SerializeAsV2 = true; + + using (var stream = new MemoryStream()) + { + using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 2048, leaveOpen: true)) + { + await documentProvider.GenerateAsync("v1", writer); + await writer.FlushAsync(); + } + + stream.Position = 0L; + + using var document = JsonDocument.Parse(stream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest2.0", swaggerInfo); + } + } + } +} diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj index 87a99d69b8..14cfb486f8 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj @@ -11,6 +11,7 @@ + diff --git a/test/Swashbuckle.AspNetCore.TestSupport/Utilities/TemporaryDirectory.cs b/test/Swashbuckle.AspNetCore.TestSupport/Utilities/TemporaryDirectory.cs new file mode 100644 index 0000000000..d6a20bac08 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.TestSupport/Utilities/TemporaryDirectory.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; + +namespace Swashbuckle.AspNetCore.TestSupport.Utilities; + +public sealed class TemporaryDirectory : IDisposable +{ + private readonly DirectoryInfo _directory = Directory.CreateDirectory(System.IO.Path.Join(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName())); + + public string Path => _directory.FullName; + + public void Dispose() + { + try + { + _directory.Delete(recursive: true); + } + catch (Exception) + { + // Ignore + } + } + + public bool Exists() => _directory.Exists; +} diff --git a/test/WebSites/CustomDocumentSerializer/Controllers/WeatherForecastController.cs b/test/WebSites/CustomDocumentSerializer/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000000..8011057792 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/Controllers/WeatherForecastController.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Mvc; + +namespace CustomDocumentSerializer.Controllers; + +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase +{ + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } +} diff --git a/test/WebSites/CustomDocumentSerializer/CustomDocumentSerializer.csproj b/test/WebSites/CustomDocumentSerializer/CustomDocumentSerializer.csproj new file mode 100644 index 0000000000..f3b09fb04f --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/CustomDocumentSerializer.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + $([System.IO.Path]::Combine('$(ArtifactsPath)', 'bin', 'Swashbuckle.AspNetCore.Cli', '$(Configuration)_$(TargetFramework)', 'dotnet-swagger.dll')) + + + + + + + + + + diff --git a/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs b/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs new file mode 100644 index 0000000000..8c88fc2390 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs @@ -0,0 +1,26 @@ +using Microsoft.OpenApi; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Writers; +using Swashbuckle.AspNetCore.Swagger; + +namespace CustomDocumentSerializer; + +public class DocumentSerializerTest : ISwaggerDocumentSerializer +{ + public void SerializeDocument(OpenApiDocument document, IOpenApiWriter writer, OpenApiSpecVersion specVersion) + { + writer.WriteStartObject(); + switch (specVersion) + { + case OpenApiSpecVersion.OpenApi2_0: + writer.WriteProperty(OpenApiConstants.Swagger, "DocumentSerializerTest2.0"); + break; + case OpenApiSpecVersion.OpenApi3_0: + writer.WriteProperty(OpenApiConstants.Swagger, "DocumentSerializerTest3.0"); + break; + default: + throw new NotImplementedException(); + } + writer.WriteEndObject(); + } +} diff --git a/test/WebSites/CustomDocumentSerializer/Program.cs b/test/WebSites/CustomDocumentSerializer/Program.cs new file mode 100644 index 0000000000..d2f9653411 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/Program.cs @@ -0,0 +1,17 @@ +namespace CustomDocumentSerializer +{ + 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/test/WebSites/CustomDocumentSerializer/Properties/launchSettings.json b/test/WebSites/CustomDocumentSerializer/Properties/launchSettings.json new file mode 100644 index 0000000000..5612e0e982 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:46561", + "sslPort": 44377 + } + }, + "profiles": { + "MinimalApp": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7160;http://localhost:5204", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/test/WebSites/CustomDocumentSerializer/Startup.cs b/test/WebSites/CustomDocumentSerializer/Startup.cs new file mode 100644 index 0000000000..de730d2101 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/Startup.cs @@ -0,0 +1,41 @@ +using Swashbuckle.AspNetCore.Swagger; + +namespace CustomDocumentSerializer; + +public class Startup +{ + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new() { Title = "CustomDocumentSerializer", Version = "v1" }); + }); + services.ConfigureSwagger(c => + { + c.SetCustomDocumentSerializer(); + }); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseSwagger(); + + app.UseHttpsRedirection(); + + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapSwagger("swagger/{documentName}/swagger.json"); + endpoints.MapSwagger("swagger/{documentName}/swaggerv2.json", c => c.SerializeAsV2 = true); + }); + } +} diff --git a/test/WebSites/CustomDocumentSerializer/WeatherForecast.cs b/test/WebSites/CustomDocumentSerializer/WeatherForecast.cs new file mode 100644 index 0000000000..35c004e522 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/WeatherForecast.cs @@ -0,0 +1,12 @@ +namespace CustomDocumentSerializer; + +public class WeatherForecast +{ + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} diff --git a/test/WebSites/CustomDocumentSerializer/appsettings.Development.json b/test/WebSites/CustomDocumentSerializer/appsettings.Development.json new file mode 100644 index 0000000000..0c208ae918 --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/test/WebSites/CustomDocumentSerializer/appsettings.json b/test/WebSites/CustomDocumentSerializer/appsettings.json new file mode 100644 index 0000000000..10f68b8c8b --- /dev/null +++ b/test/WebSites/CustomDocumentSerializer/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/test/WebSites/NswagClientExample/swagger.json b/test/WebSites/NswagClientExample/swagger.json index 47359163c7..d533a1b350 100644 --- a/test/WebSites/NswagClientExample/swagger.json +++ b/test/WebSites/NswagClientExample/swagger.json @@ -102,34 +102,38 @@ "type": "string" }, "Cat": { - "type": "object", "allOf": [ { "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false } - ], - "properties": { - "catSpecificProperty": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false + ] }, "Dog": { - "type": "object", "allOf": [ { "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false } - ], - "properties": { - "dogSpecificProperty": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false + ] } } }