Swashbuckle.aspnetcore: CLI is not working with project referencing Autofac

Created on 26 Jun 2019  路  17Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

Repro steps:

  1. Add swashbuckle nuget packages to the project:

    • SwashBuckle.AspNetCore 4.0.1

    • SwashBuckle.AspNetCore.Annotations 4.0.1

  1. Configure swashbuckle:
  2. In ConfigureServices:
services.AddSwaggerGen(options =>
{
    var projectName = GetType().Assembly.GetName().Name;
    var path = Path.Combine(AppContext.BaseDirectory, $"{projectName}.xml");

    options.SwaggerDoc("v1", new Info
    {
        Title = $"{projectName} API Reference",
        Version = "v1"
    });

    options.IncludeXmlComments(path, true);
    options.EnableAnnotations();
});
  • In Configure:
app.UseSwagger();
app.UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"));

Swashbuckle & Swagger UI now works fine

  1. Add DotNetCliToolReference to .csproj file:
  <ItemGroup>
    <DotNetCliToolReference Include="Swashbuckle.AspNetCore.Cli" Version="4.0.1" />
  </ItemGroup>
  1. Run
dotnet swagger tofile --output swaggerexport.json path\to\project.dll v1
  1. Got an error
Unhandled Exception: System.InvalidOperationException: No service for type 'Microsoft.Extensions.DependencyInjection.IServiceProviderFactory`1[Autofac.ContainerBuilder]' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.StartupLoader.ConfigureServicesDelegateBuilder`1.<>c__DisplayClass14_0.<ConfigureServices>g__ConfigureServicesWithContainerConfiguration|0(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Swashbuckle.AspNetCore.Cli.Program.<>c.<Main>b__0_3(IDictionary`2 namedArgs)
   at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args)
   at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args)
   at Swashbuckle.AspNetCore.Cli.Program.Main(String[] args)

All 17 comments

You'll need something like this #887 to create your WebHost.

I have the exact same issue. Were you able to resolve this?

Is there a work around for this isse?

@patriksvensson It's not pretty but we had success cloning the Swashbuckle.AspNetCore.Cli project and applying the PR #887 mentioned above.

In the end, we actually simplified it further by pulling in the specific project we're creating swagger typings for and replacing this block with class specific types. That does make for a pretty gnarly set of dependencies, plus the added hassle of keeping in step with patches, but it is a work around of sorts if you're desperate!

@andrewbridge Thanks for the reply! Will probably just fork Swashbuckle until this PR is getting merged (or fixed another way).

It's been a while, so I'll need a bit of time to regain the context. I'm working on another area right now, but reviewing the PR, resolving conflicts etc. is next on the list. So, stay tuned ...

I just merged #887 to fix this issue. However, I've sinced discovered a subsequent problem with the approach. The PR introduces the new interface ISwaggerWebHostFactory, and if your application includes an implementation of that interface, then the CLI tool will use it to create an IWebHost to run the CLI through.

However, the Swashbuckle.AspNetCore.Cli package is a .NET Global Tool, and therefore can't be added to your project as a regular dependency. If you can't add the dependency, then you won't have access to the ISwaggerWebHostFactory type, and will therefore be blocked from _actually using_ the new capability.

There's two immediate workarounds that come to mind:

1) Use a naming convention rather than a strongly-typed inteface for the application hook (e.g. a static class named "SwaggerWebHostFactory" with a method called "CreateWebHost")
2) Introduce an additional package for the sole purpose of defining the ISwaggerWebHostFactory interface.

Thoughts?

@domaindrivendev Thanks for taking the time to resolve this issue! I'm excited to get spec generation restarted in my project.

As for your solutions, my vote would be a naming convention, just because I'm generally in favor of keeping dependencies to a minimum, but certainly either could work. However, either way, I think it would be great if the CLI could fail fast and specify exactly what consumers need to do if they haven't properly configured their project, whether it's defining this static class or installing the additional package.

Is there a resolution for this? With upgrading our project from .Net core 2.2 to .Net core 3.1 and also from StructureMap (IoC) to Lamar, I am facing this issue:

Unhandled exception. System.InvalidOperationException: No service for type 'Microsoft.Extensions.DependencyInjection.IServiceProviderFactory1[Lamar.ServiceRegistry]' has been registered. at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.AspNetCore.Hosting.StartupLoader.ConfigureServicesDelegateBuilder1.<>c__DisplayClass14_0.g__ConfigureServicesWithContainerConfiguration|0(IServiceCollection services)
at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
at Microsoft.AspNetCore.Hosting.WebHost.EnsureApplicationServices()
at Microsoft.AspNetCore.Hosting.WebHost.Initialize()
at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
at Swashbuckle.AspNetCore.Cli.Program.BuildWebHost(Assembly startupAssembly) in C:projectsahoysrcSwashbuckle.AspNetCore.CliProgram.cs:line 142
at Swashbuckle.AspNetCore.Cli.Program.<>c.

b__0_3(IDictionary2 namedArgs) in C:\projects\ahoy\src\Swashbuckle.AspNetCore.Cli\Program.cs:line 68 at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable1 args) in C:projectsahoysrcSwashbuckle.AspNetCore.CliCommandRunner.cs:line 68
at Swashbuckle.AspNetCore.Cli.CommandRunner.Run(IEnumerable`1 args) in C:projectsahoysrcSwashbuckle.AspNetCore.CliCommandRunner.cs:line 68
at Swashbuckle.AspNetCore.Cli.Program.Main(String[] args) in C:projectsahoysrcSwashbuckle.AspNetCore.CliProgram.cs:line 107

Swashbuckle.AspNet.Core: 5.2.1
"tools": {
"swashbuckle.aspnetcore.cli": {
"version": "5.2.1",
"commands": [
"swagger"
]
}
}

@shivanaru We ran into a very similar error with Autofac trying to generate the Open API document, though using Swasbuckle/CLI version 5.3.1:

No service for type 'IServiceProviderFactory[Autofac.ContainerBuilder]' has been registered

We worked around this by using the SwaggerWebHostFactory instead of SwaggerHostFactory. Our main app is still built & run using a generic host configuration, but we use the .NET Core 2 style WebHost just for static spec generation:

WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(s => s.AddAutofac())
    .UseStartup<Startup>()
    .Build();

I don't know if this applicable to your particular situation, but it helped us.

Hi all,

Doesn't look like i can add Swashbuckle.AspNetCore.Cli to 3.1 projects, therefore i can't reference ISwaggerWebHostFactory. Do I have another option?

Thanks!

@MarkLeMerise Do you have a 2nd app that references the 1st app so you can reference the controllers?

edit:
So i just added
public static class SwaggerHostFactory { public static IHost CreateHost() { return CreateHostBuilder(null).Build(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
stupid markdown

and it now can successfully build as long as i commented out my "ConfigureContainer" method specified by Autofac. This is where i register modules for mediatr to work. All my controllers have a mediatr dependency so i am unable to get any operations in my swagger.json

Has anyone found a way to solve this?

edit p2:
Added my own Startup.cs specifically for this. Just excluded all unnecessary things, and now it seems like things just magically worked. No idea why.

Hi all,

Doesn't look like i can add Swashbuckle.AspNetCore.Cli to 3.1 projects, therefore i can't reference ISwaggerWebHostFactory. Do I have another option?

Thanks!

I moved to using NSwag and it works well with Open API/Swagger v3 spec. We also needed to generate the TypeScript interfaces and NSwag does that as well. Was easy to configure as well.
Hope that helps!

@MattHartz

Doesn't look like i can add Swashbuckle.AspNetCore.Cli to 3.1 projects, therefore i can't reference ISwaggerWebHostFactory. Do I have another option?

Yeah, just use NSwag 馃槢 Judging from your following comments, it sounds like you did get the tool installed. As a test, I switched my project to .NET 3.1 (from 3.0) and didn't have any issues restoring the CLI tool and generating the Open API document.

Do you have a 2nd app that references the 1st app so you can reference the controllers?

No second app. My Web project contains all the controllers and SwaggerWebHostFactory. The dotnet swagger command runs as a post-build step on this Web project (per the Swashbuckle docs).

...and it now can successfully build as long as i commented out my "ConfigureContainer" method specified by Autofac.

Per my previous comment, I'm using the SwaggerWebHostFactory because trying to build a generic IHost (via SwaggerHostFactory) with an Autofac container didn't seem to play nicely with the Swashbuckle CLI.

@MarkLeMerise Yeah, that's what I ultimately ended up doing. You can kinda tell in that little code section I posted. I had to read to code to see what I literally was looking for IHost or whatever.

Thanks for responding! :)

Had the same issue and I got kinda confused by the replies here.

What fixed it for me was adding this:

public class SwaggerHostFactory
{
    public static IHost CreateHost()
    {
        return Program.CreateHostBuilder(new string[0]).Build();
    }
}

This is a separate file from my normal Program.cs, just added it, and seems to work fine.

My use case was that I needed the OpenApi generated at build time so I could generate Typescript services from it (just in case someone is having the same issue).

The above code and this did the trick:

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
   <Exec Command="swagger tofile --output swagger.json $(OutputPath)\$(AssemblyName).dll v1" />
</Target>
Was this page helpful?
0 / 5 - 0 ratings