Swashbuckle.AspNetCore icon indicating copy to clipboard operation
Swashbuckle.AspNetCore copied to clipboard

Swashbuckle CLI does not work with the new Minimal Hosting Model in .NET 6

Open brennfoster opened this issue 3 years ago • 14 comments

Swashbuckle CLI seems to skip the Program.cs file and look directly at the Startup.cs file to generate the swagger doc. However, the minimal hosting model gets rid of the Startup.cs file in favor of a single Program.cs file to register services. Because of this, I am getting errors when running "dotnet swagger tofile" command.

My use case involves pulling app settings from a key vault when the app starts. Because Swashbuckle CLI isn't aware of environment variables (which don't even exist in devops pipelines), I get the below error: Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'vault')

I noticed there is a feature request to stop running the app when the "dotnet swagger tofile" command is run here: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2181 This feature seems a lot more important now that Microsoft has introduced this new pattern.

brennfoster avatar Dec 08 '21 23:12 brennfoster

For anyone else who is experiencing this problem, the work around is to continue using a Startup class as described here: https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio#use-startup-with-the-new-minimal-hosting-model

brennfoster avatar Dec 09 '21 16:12 brennfoster

Is this planned to get fixed?

Lancelotbronner avatar Jan 02 '23 19:01 Lancelotbronner

current CI/CD file generated by azure gives the same error.

image

StanlyLife avatar Feb 03 '23 08:02 StanlyLife

Hi, Is the issue resolved? I am facing exactly the same issue. Please help !!!

sushantkadam17 avatar Mar 29 '23 20:03 sushantkadam17

Same issue with .NET 8...

Stratis-Dermanoutsos avatar Dec 11 '23 21:12 Stratis-Dermanoutsos

+1 Also just encountered

josephworks avatar Mar 04 '24 08:03 josephworks

Same here with .NET 8 Minimal API

thangchung avatar Mar 08 '24 04:03 thangchung

I'm seeing this in a .NET6 Api with Program.cs clas

MitchellW-DWL avatar Mar 08 '24 15:03 MitchellW-DWL

Same here with .NET 8 Minimal API

Was this fixed ? Also .NET 8 Minimal API

Bouallegui-Moudhaffer avatar Mar 29 '24 16:03 Bouallegui-Moudhaffer

Just tested, still broken.

josephworks avatar Mar 30 '24 04:03 josephworks

@brennfoster you can specify environment variable yourself. <Target Name="SwaggerToFile" AfterTargets="AfterBuild"> <Exec Condition="$(CI) != true" Command="dotnet swagger tofile --host http://example.com --output ../../../frontend/cv-ui/libs/api/src/lib/v1.json $(OutputPath)$(AssemblyName).dll v1" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development;DOTNET_ROLL_FORWARD=LatestMajor" /> </Target> I have working minimal API without old startup.ca

Lonli-Lokli avatar Apr 14 '24 10:04 Lonli-Lokli

Another workaround:

The class SwaggerRunDetector trys to detect if the swagger tool is running the app. If so I do not execute code segments which should not run when generating the specification e.g. connect to a DB. The instance can be retreived from DI to do checks:

if (app.Services.GetRequiredService<SwaggerRunDetector>().IsSwaggerToolRun())
{
   // e.g. return from function or do not start service
}
using System.Reflection;

namespace TheNamespace.Util.WebApi.OpenApi;

/// <summary>
/// Detects if the current app run is triggered by swagger tool.
/// Swagger tool to generate OpenApi spec will run the application in the new hosting model
/// since it needs the DI container.
/// Starting the app or sub processes my not be possible e.g. during CI/CD.
/// see https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2290
/// </summary>
public class SwaggerRunDetector
{
    private readonly ILogger logger;

    public SwaggerRunDetector(ILogger<SwaggerRunDetector> logger)
    {
        this.logger = logger;
    }

    /// <summary>
    /// Detect if current app run is triggered by swagger
    /// </summary>
    /// <returns>True if the current execution is a swagger generation run.</returns>
    public bool IsSwaggerToolRun()
    {
        logger.LogTrace("Detecting swagger run: GetEntryAssembly: {entryAssembly}", Assembly.GetEntryAssembly()!.FullName);
        
        var entryAssembly = Assembly.GetEntryAssembly()?.FullName;
        var isSwaggerRun = !string.IsNullOrWhiteSpace(entryAssembly) && entryAssembly.Contains("swagger", StringComparison.InvariantCultureIgnoreCase);
        logger.LogTrace("Swagger run: {isSwaggerRun}", isSwaggerRun);
        return isSwaggerRun;
    }
}

For completeness the build target to generate the openapi.json:

<Target Name="OpenAPI" DependsOnTargets="Build">
  <Exec Command="swagger tofile --output ./openapi.json $(OutputPath)$(AssemblyName).dll v1" WorkingDirectory="$(ProjectDir)" />
</Target>

It has its own problems, e.g. polluting the code with swagger specific conditions and it uses (slow?) reflection. But maybe it still helps someone.

MathiasReichardt avatar Apr 16 '24 14:04 MathiasReichardt

Same issue with .NET 8...

I don't understand if this is fixed or why this issue is still open. But I am surprised some people are finding this problem with .NET 8. I created a few samples for .NET 8 https://github.com/diegosasw/sample-open-api

and a CI/CD GitHub Actions pipeline (can be tested locally, of course)

- name: Generate Swagger for WebApiOne
   run: dotnet swagger tofile --output temp/web-api-one.json src/WebApiOne/bin/Release/net8.0/WebApiOne.dll web-api-one

- name: Generate Swagger for WebApiTwo
   run: dotnet swagger tofile --output temp/web-api-two.json src/WebApiTwo/bin/Release/net8.0/WebApiTwo.dll web-api-two

and it's generating the open api json properly despite using minimal API and having Program.cs but not Startup.cs

Am I missing something?

PS: I'm using this dotnet tool

{
  "version": 1,
  "isRoot": true,
  "tools": {
    "swashbuckle.aspnetcore.cli": {
      "version": "6.6.2",
      "commands": [
        "swagger"
      ],
      "rollForward": false
    }
  }
}

diegosasw avatar Jun 28 '24 10:06 diegosasw

@diegosasw Your sample projects don't appear to be pulling any values from environment variables or configuration so they won't encounter the issue. I believe that this issue is the same (or very similar) to another that I have posted a bare-bones repro in if you're interested in seeing the error: https://github.com/dotnet/aspnetcore/issues/45025#issuecomment-2161711924

EvanSchallerer avatar Jul 03 '24 00:07 EvanSchallerer