domaindrivendev / Swashbuckle.AspNetCore

Swagger tools for documenting API's built on ASP.NET Core
MIT License
5.25k stars 1.31k forks source link

Swashbuckle CLI lacks support for minimal APIs with .NET 6 #2168

Closed bradygaster closed 1 year ago

bradygaster commented 3 years ago

We're trying out various Swashbuckle-enabled scenarios with the upcoming Minimal APIs feature, and noted that it appears to not work out-of-the-gate with the new style of development.

I created a basic minimal API, then added Swashbuckle to it and got both the OpenAPI description and Swagger UI working using the following code with the RC1 preview bits.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c => 
{
    c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
    {
        Title = "Minimal API",
        Version = "v1"
    });
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapGet("/", () => "Hello World!");

app.Run();

Things work fine in the "run" scenario. Yet, when I execute the CLI command as such:

swagger tofile --host https://localhost:5001 MinimalWithSwashbuckle.dll v1

I get an error indicating that the code would need a Startup class to interrogate to work.

Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly 'MinimalWithSwashbuckle'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName) in Microsoft.AspNetCore.Hosting.dll:token 0x6000136+0x14c
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors) in Microsoft.AspNetCore.Hosting.dll:token 0x6000189+0x2de
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_2.<BuildCommonServices>b__5(IServiceProvider _) in Microsoft.AspNetCore.Hosting.dll:token 0x6000289+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000094+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x23
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008e+0x61
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a5+0x4e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008b+0x26
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000068+0x38
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) in System.Collections.Concurrent.dll:token 0x60000d3+0x4f
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000066+0xd
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000061+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) in Microsoft.Extensions.DependencyInjection.Abstractions.dll:token 0x6000094+0xe
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureStartup() in Microsoft.AspNetCore.Hosting.dll:token 0x600014b+0x9
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices() in Microsoft.AspNetCore.Hosting.dll:token 0x600014a+0x8
   at Microsoft.AspNetCore.Hosting.WebHost.Initialize() in Microsoft.AspNetCore.Hosting.dll:token 0x6000147+0x0
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() in Microsoft.AspNetCore.Hosting.dll:token 0x6000188+0x9a
   at Swashbuckle.AspNetCore.Cli.Program.GetServiceProvider(Assembly startupAssembly) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 133
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_3(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 72
   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 111
bradygaster commented 3 years ago

@domaindrivendev I was chatting with @captainsafia @brennanconroy and @davidfowl about this and we're prepared to create a PR but just wanted to make sure we know what you'd expect. Proposing a list below.

Let us know if this is accurate and we'll get on it. As well, we'd like to know an expectation on turnaround time once the PR comes in as we're trying to ready this against other items and would appreciate it if you could give us an expectation.

As always, we appreciate the support.

also cc @phil-allen-msft as this has publishing implications so once it ships it'll be good.

domaindrivendev commented 3 years ago

Sounds good @bradygaster đź‘Ť

Regarding turnaround - if the changes are non-breaking, I think we can get them out pretty quick (i.e. days, not weeks). The only delay would be around reviewing the changes. To help with this, I would ask that you strive for minimal PR's that focus squarely on the desired functionality.

stevenknox commented 2 years ago

Is there a temporary workaround for this to start generating clients again for Net 6 Minimal APIs?

davidfowl commented 2 years ago

It should work now

stevenknox commented 2 years ago

Ahh thank you, I hit this issue yesterday and first google for the issue landed me here. I just checked everything again after your comment and noticed Swashbuckle.AspNetCore.Cli was an older version. Updated and all now working as expected .

Thanks

jvos-priva commented 2 years ago

I am already using 6.2.3 and this all used to work until I added the following line in my code, after which it failed with the same exception as mentioned by the original poster:

builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["keyvault:name"]}.vault.azure.net/"),
        new DefaultAzureCredential());

I am using .NET 6 top level statements template but with a full blown API. Does anyone have any ideas?

For reference the full exception stack trace:

Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly 'Priva.AssetManagement.Api'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_2.<BuildCommonServices>b__5(IServiceProvider _)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.WebHost.Initialize()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Swashbuckle.AspNetCore.Cli.Program.GetServiceProvider(Assembly startupAssembly) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 145
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 82
   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
jvos-priva commented 2 years ago

After some digging I figured out the problem. Even though the error is the same, the root cause is unrelated. I created a separate issue for it: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2355

julealgon commented 2 years ago

I just ran into this exact same problem and I'm not using minimal APIs: this appears to be an issue related to the simplified top-level program setup.

Upon running the cmd against my DLL, I get an error instantaneously:

dotnet swagger tofile --output c:\sample.json {pathToMyAssembly} v1
Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly '{myAssembly}'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_2.<BuildCommonServices>b__5(IServiceProvider _)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.WebHost.Initialize()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Swashbuckle.AspNetCore.Cli.Program.GetServiceProvider(Assembly startupAssembly) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 145
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 82
   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

Just to see what would happen, I created an empty Startup class somewhere with a void Configure method. Then, this is what I get after running the command again (seems like it really is looking for a startup class there):

Unhandled exception. System.InvalidOperationException: No service for type 'Swashbuckle.AspNetCore.Swagger.ISwaggerProvider' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 82
   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

I'm using version 6.3.1 of the CLI package.

I need to obtain the swagger doc during my pipeline build to update Azure API Management. Any help is appreciated.

EDIT:

As per what @jvos-priva above mentioned, it appears that exceptions in the setup are causing this package to raise unrelated errors.... after adding System.Diagnostics.Debugger.Launch to my startup, I can see it is trying to obtain production settings and throwing a InvalidOperationException.

It seems to be hosting the API in default production mode, which causes appsettings.Production.config to be read... my app doesn't have all production settings in that file, some of the settings come through the hosting environment through environment variables in Azure.

How am I supposed to run this without forcing production mode? I don't see any flags in the tool help to change it.

EDIT 2:

Ok, I made it work by temporarily replacing a configuration.GetRequiredSection call with configuration.GetSection. After that, it was a only a matter of running the tool from the correct folder and it worked. I was running the tool from the solution root instead of the actual API project root, meaning it wasn't even loading my appsettings.json properly and causing other errors (I assume it hosts considering the callsite as the main folder, so if no config files exist at that level, nothing is loaded).

Not happy with the fact that I had to make my code more brittle however... the GetRequiredSection call was there for a purpose: to warn me in case configuration values were missing during startup. Oh well... I'll have to rethink some of this.

average04 commented 2 years ago

Ran into same problem on Workflow while publishing on azure. This is also minimal API

Run swagger tofile --output "Minimal/Minimal.API/publish/swagger.json" "Minimal/Minimal.API/publish/Minimal.API.dll" "v1"

Error

Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly 'Minimal.API'.

Hope somebody can help

davidfowl commented 2 years ago

Is everything updated to the latest? .NET 6 and swashbuckle?

average04 commented 2 years ago

Is everything updated to the latest? .NET 6 and swashbuckle?

Updated to the latest. It's working now, Thanks a lot

boukeversteegh commented 2 years ago

This is a very confusing error. In my real problem was also unrelated, just an error while launching swagger with a different environment (missing config values).

Assume that the problem is not with swagger:

deivydas321 commented 1 year ago

The issue still occurs with .NET 6. Created a very simple .NET 6 API with swagger. All nuggets are the latest. And created a default publish profile with GitHub actions.

It fails in step: Generate open api specification

Here's the error:

Run swagger tofile --output "X/publish/swagger.json" "X/bin/Release/net6.0/X.dll" "v1"
Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly 'SimpleIp'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_2.<BuildCommonServices>b__5(IServiceProvider _)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.WebHost.Initialize()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Swashbuckle.AspNetCore.Cli.Program.GetServiceProvider(Assembly startupAssembly) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 1[33](https://github.com/deivyd321/SimpleIp/actions/runs/3756652695/jobs/6382960137#step:10:34)
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_3(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 72
   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 111
Error: Process completed with exit code 1[34]
davidfowl commented 1 year ago

@deivyd321 Can you provide repro steps with a sample project?

OpenSpacesAndPlaces commented 1 year ago

Should this thread be closed? Running into the same issues on .Net 7.0

System.InvalidOperationException: A type named 'Startuplocalhost' or 'Startup' could not be found in assembly 'MarketCarpenter-6'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.ScanAssemblyAndRegisterStartup(ServiceCollection services, String startupAssemblyName)

Current workaround is to manually generate first:

using (var outputString = new StringWriter())
        {
            var writer = new OpenApiJsonWriter(outputString);
            swaggerDoc.SerializeAsV3(writer);
            File.WriteAllText( "...MyDrivePath.../swagger.json", outputString.ToString());
        }

But it was nice that the CLI could be baked into node startup or builds.

bradygaster commented 1 year ago

cc @captainsafia FYI

nkoudelia commented 1 year ago

The dotnet new webapi command creates a project file with an outdated Swashbuckle.AspNetCore reference. That's where the error is coming from. Just updated it to the same version with the tool (6.5.0 atm.) and everything is working fine.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RootNamespace>web_api</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

</Project>
captainsafia commented 1 year ago

The dotnet new webapi command creates a project file with an outdated Swashbuckle.AspNetCore reference. That's where the error is coming from. Just updated it to the same version with the tool (6.5.0 atm.) and everything is working fine.


<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>

    <TargetFramework>net6.0</TargetFramework>

    <Nullable>enable</Nullable>

    <ImplicitUsings>enable</ImplicitUsings>

    <RootNamespace>web_api</RootNamespace>

  </PropertyGroup>

  <ItemGroup>

    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />

  </ItemGroup>

</Project>

@nkoudelia Can you open a bug on the ASP.NET Core repo for this? We can see about patching the 6.0 templates to pick up the fixed package version.

bryanjtc commented 1 year ago

Any update on this?

captainsafia commented 1 year ago

I've opened https://github.com/dotnet/aspnetcore/pull/47860 to update the version of the package referenced in the .NET 6 templates to the latest release. This should resolve the issue. If there are any problems happening that aren't resolved by updating the latest version, filing an ew issue would be helpful so we can track it down.

Patrick-Davis-MSFT commented 1 year ago

This also should be updated in the GitHub Actions template under the environment variable SWASHBUCLE_ASPNET_CORE_CLI_PACKAGE_VERSION:

Set it to 6.5.0 if anyone is looking for the solution to the same issue running GitHub actions.

MortenMeisler commented 1 year ago

I just ran into this exact same problem and I'm not using minimal APIs: this appears to be an issue related to the simplified top-level program setup.

Upon running the cmd against my DLL, I get an error instantaneously:

dotnet swagger tofile --output c:\sample.json {pathToMyAssembly} v1
Unhandled exception. System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly '{myAssembly}'.
   at Microsoft.AspNetCore.Hosting.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_2.<BuildCommonServices>b__5(IServiceProvider _)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.WebHost.Initialize()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Swashbuckle.AspNetCore.Cli.Program.GetServiceProvider(Assembly startupAssembly) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 145
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 82
   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

Just to see what would happen, I created an empty Startup class somewhere with a void Configure method. Then, this is what I get after running the command again (seems like it really is looking for a startup class there):

Unhandled exception. System.InvalidOperationException: No service for type 'Swashbuckle.AspNetCore.Swagger.ISwaggerProvider' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_4(IDictionary`2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 82
   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

I'm using version 6.3.1 of the CLI package.

I need to obtain the swagger doc during my pipeline build to update Azure API Management. Any help is appreciated.

EDIT:

As per what @jvos-priva above mentioned, it appears that exceptions in the setup are causing this package to raise unrelated errors.... after adding System.Diagnostics.Debugger.Launch to my startup, I can see it is trying to obtain production settings and throwing a InvalidOperationException.

It seems to be hosting the API in default production mode, which causes appsettings.Production.config to be read... my app doesn't have all production settings in that file, some of the settings come through the hosting environment through environment variables in Azure.

How am I supposed to run this without forcing production mode? I don't see any flags in the tool help to change it.

EDIT 2:

Ok, I made it work by temporarily replacing a configuration.GetRequiredSection call with configuration.GetSection. After that, it was a only a matter of running the tool from the correct folder and it worked. I was running the tool from the solution root instead of the actual API project root, meaning it wasn't even loading my appsettings.json properly and causing other errors (I assume it hosts considering the callsite as the main folder, so if no config files exist at that level, nothing is loaded).

Not happy with the fact that I had to make my code more brittle however... the GetRequiredSection call was there for a purpose: to warn me in case configuration values were missing during startup. Oh well... I'll have to rethink some of this.

This was exactly my problem.

3 workarounds: 1) As you suggested, use GetSection instead of GetRequiredSection (not the best) 2) Create a appsettings.Production.json file (appsettings.Prod does not work) 3) Skip appsettings.Production.json and make sure the section is located in the appsettings.json file as this is the fallback

It's the same issue with Nswag btw.

MitchellW-DWL commented 1 month ago

Don't suppose there's any movement on this? I'm still seeing it on 6.5.0 and 6.8.0 with .net8

martincostello commented 1 month ago

@MitchellW-DWL https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2168#issuecomment-1520497113