ASP.NET Core allows you to create an Open API specification file through Swashbuckle. By default Swashbuckle will generate the OpenAPI documentation at runtime, but did you know that it is also possible to do this at build time?
Doing this at build time helps us to reduce application startup time and also gives use the possibility to start serving the OpenAPI specification file from a CDN.
Let us walk through the steps to achieve this…
First we need to create a tool manifest file so we call the Swashbuckle CLI tooling:
dotnet new tool-manifest
Now we can install the CLI tooling:
dotnet tool install SwashBuckle.AspNetCore.Cli
Let’s invoke the tooling to create the swagger.json file:
dotnet swagger tofile --output [output] [startupassembly] [swaggerdoc]
where ...
- [output] is the relative path where the Swagger JSON will be output to
- [startupassembly] is the relative path to your application's startup assembly
- [swaggerdoc] is the name of the swagger document you want to retrieve, as configured in your startup class
Here is a concrete example:
dotnet swagger tofile --output ./wwwroot/swagger/v1/swagger.json bin\debug\net6.0\SwaggerExample.dll v1
Swagger JSON/YAML successfully written to D:\Projects\SwaggerExample\./wwwroot/swagger/v1/swagger.json
Important: Before you execute the command above you should check 2 things:
1. Check that the tool version corresponds with the Swashbuckle.AspNetCore
version that you installed on your project. In my case the version was different and this resulted in the following error:
Unhandled exception. System.IO.FileLoadException: Could not load file or assembly 'Swashbuckle.AspNetCore.Swagger, Version=6.4.0.0, Culture=neutral, PublicKeyToken=62657d7474907593'. The located assembly's manifest definition does not match the assembly reference. (0x80131040)
File name: 'Swashbuckle.AspNetCore.Swagger, Version=6.4.0.0, Culture=neutral, PublicKeyToken=62657d7474907593'
at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs)
at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\CommandRunner.cs:line 68
at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\CommandRunner.cs:line 59
at Swashbuckle.AspNetCore.Cli.Program.Main(String[] args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 121
To get rid of this error I updated my csproj file to align the Swashbuckle.AspNetCore versions:
2. Create the target folder where you want to write the swagger.json
up front. If you forget to do this, you’ll get the following error message:
Unhandled exception. System.IO.DirectoryNotFoundException: Could not find a part of the path 'D:\Projects\Test\WebAPITraining\WebAPITrainingTake2\wwwroot\swagger\v1\swagger.json'.
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preal at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.File.CreateText(String path)
at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 100
at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\CommandRunner.cs:line 68
at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\CommandRunner.cs:line 59
at Swashbuckle.AspNetCore.Cli.Program.Main(String[] args) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 121
Of course it is easier that the tooling is automatically invoked each time we build our project. Therefore update our csproj file:
Now we no longer need the Swagger middleware and can server the swagger.json using the static files middleware:
Happy coding!