Swashbuckle.webapi: Cannot read swagger.json error when hosted as an application under a website on IIS

Created on 6 Jan 2017  路  22Comments  路  Source: domaindrivendev/Swashbuckle.WebApi

Hi, All:

We are having an issue when implement swagger to our dotnetcore api (is there a support forum for this kind of discussion?). When we host the API as a new website, the swagger works perfectly. But when we host the API as an application under a website, we got the "cannot read swagger.json" error. Following is the sites structure on our IIS.

StartPage
MyServerName
Application Pools
    Sites
        Default Web Site
        MyAPI_Working
        MySite
             MyAPI_NotWorking

For the MyAPI_Working site, when access via http://servername:port/swagger/ui/index.html. we see the swagger ui beautifully.

But for the MySite/MyAPI_NotWorking, when access via http://servername:port/MyAPI_NotWorking/swagger/ui/index,html.
It shows "Can't read swagger JSON from http://servername:port/swagger/v2/swagger.json.".
If we change the URL in the swagger textbox to
http://servername:port/MyAPI_NotWorking/swagger/v2/swagger.json.
We got the correct swagger ui.

Seems like Swagger default to read from the path under the site directly. but the swagger output the json file to "http://servername:port/**MyAPI_NotWorking/" (the json file from xml comments).

We did see the UseSwaggerUi() function accepts baseRoute and SwaggerUrl parameters, but we just could get it to work.

Here is some code snippet for what we are doing:

    private void ConfigureSwaggerGen(IServiceCollection services)
    {
        services.AddSwaggerGen(config =>
        {
            config.SingleApiVersion(new Info
            {
                Version = "v1",
                Title = "MyTest DotNetCore API Service",
                Description = "A DotNetCore API Service."
            });
            config.IncludeXmlComments(GetXmlCommentsPath()); 
        });
    }

    public void Configure(IApplicationBuilder appBuilder)
    {
        appBuilder.UseMvc();

        appBuilder.UseSwagger();
        appBuilder.UseSwaggerUi();
    }

Any tips will be very much appreciated. Thanks in advance.
-Rockdale

Most helpful comment

adding a relative path worked for me

            app.UseSwaggerUI(s => {
                s.RoutePrefix = "help";
                s.SwaggerEndpoint("../swagger/v1/swagger.json", "MySite");
                s.InjectStylesheet("../css/swagger.min.css");
            });

All 22 comments

You have to add the virtual directory path for Json and then it will work
app.UseSwaggerUi(swaggerUrl: Configuration["AppSettings:VirtualDirectory"] + "/swagger/v1/swagger.json")

Thank you for your reply.

We are using dotnetcore REST API, we do not have app (Is that a Asp.Net application?) nor do we have AppSettings - and the VirtualDirectory is configured in IIS, our code does not have knowledge of what the directory name it is configured in the IIS.

Or did I miss something here?

Here is how I solved it about 5 mins ago

Install NuGet Packages

  • Install-Package Swashbuckle.AspNetCore.SwaggerGen -Pre ( I had to use the package manager console)

In Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Swashbuckle.AspNetCore.Swagger;

namespace Sample.Api
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
        services.AddSwaggerGen(c =>

{
c.SwaggerDoc("v1", new Info { Title = "My Sample API", Version = "v1" });
});
}

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseMvc();

        app.UseSwagger(c => 
        {
            c.RouteTemplate = "swagger/{documentName}/swagger.json";
        });

        app.UseSwaggerUi(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        }); 
    }
}

}

In launchSettings.json (if you are using VS 2017)

"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5000",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Sample.Api": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:5000"
}
}
}

Run using IIS or Kestrel and voila

adding a relative path worked for me

            app.UseSwaggerUI(s => {
                s.RoutePrefix = "help";
                s.SwaggerEndpoint("../swagger/v1/swagger.json", "MySite");
                s.InjectStylesheet("../css/swagger.min.css");
            });

@scastaldi - Relative path solution works perfect!! Thank you for saving the time :)

Given that the path you specify here is relative to the UI page itself, and the Swagger JSON URL builds on that, you Should be able to clean up further ...

c.SwaggerDoc("v1/swagger.json", ...)

With c # and Net core if you use several methods with the decorator [HttpPost (". {Format?}"), FormatFilter] the /swagger/v1/swagger.json file can not be generated obviously because of the ambiguity of all the POST methods with the same {format?}.

Try this:
app.UseSwaggerUI(c =>
{
string swaggerJsonBasePath = string.IsNullOrWhiteSpace(c.RoutePrefix) ? "." : "..";
c.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/v1/swagger.json", "My API");
});

this solution works fine (thanks ylhyh)

        app.UseSwaggerUI(
            options =>
            {
                string swaggerJsonBasePath = string.IsNullOrWhiteSpace(options.RoutePrefix) ? "." : "..";

                foreach (var description in provider.ApiVersionDescriptions)
                {
                    options.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                }
            });

Relative path works on localhost and IIS host, thanks!

this solution works fine (thanks ylhyh)

        app.UseSwaggerUI(
            options =>
            {
                string swaggerJsonBasePath = string.IsNullOrWhiteSpace(options.RoutePrefix) ? "." : "..";

                foreach (var description in provider.ApiVersionDescriptions)
                {
                    options.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                }
            });

This work even better

c# app.UseSwaggerUI(__options => { foreach (var versionDescription in provider.ApiVersionDescriptions) { __options.SwaggerEndpoint($"../{__options.RoutePrefix}/{versionDescription.GroupName}/swagger.json", versionDescription.GroupName.ToUpperInvariant()); } if (!string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(clientSecret)) { __options.OAuthClientId(clientId); __options.OAuthClientSecret(clientSecret); } });

adding a relative path worked for me

            app.UseSwaggerUI(s => {
                s.RoutePrefix = "help";
                s.SwaggerEndpoint("../swagger/v1/swagger.json", "MySite");
                s.InjectStylesheet("../css/swagger.min.css");
            });

this one worked for me also.... all other methods failed.
thank you

apparently its case sensitive too. mine got fixed after below change - see V2 vs v2
//c.SwaggerEndpoint("/creation-services/V2/swagger.json", "CreationServices V2");
c.SwaggerEndpoint("/creation-services/v2/swagger.json", "CreationServices V2");

Hi, i had this problem and solved it by delete the .vs catalog in project catalog. It seems lik my problem was i had tested it with iis and created an application and in some way it failed in express as well.

For me, it was a problem with a route in a controller which was duplicated!
To resolve this kind of problem maybe It's better to open swagger/v1/swagger.json in a browser and read the error to get some information about it.

adding a relative path worked for me

            app.UseSwaggerUI(s => {
                s.RoutePrefix = "help";
                s.SwaggerEndpoint("../swagger/v1/swagger.json", "MySite");
                s.InjectStylesheet("../css/swagger.min.css");
            });

This worked for me too. I'm using Swashbuckle.AspNetCore" Version="4.0.1"
Thank you!!

hey, i had the same issue, and resolved...
solution:
setupAction.SwaggerDoc("v1.0", new Info
{
Version = "v1.0",
Title = "Some API"
});
use the same version (v1.0) in "/api/swagger/v1.0/swagger.json"
setup.RoutePrefix = "api";
setup.SwaggerEndpoint("/api/swagger/v1.0/swagger.json", "v1.0");

I have the following (using .net core 3.1 and trying to host on IIS) :

c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "API",
                    Version = "v1",
                    Description = "API"
                });

and

app.UseSwaggerUI(c =>
            {
                string swaggerJsonBasePath = string.IsNullOrWhiteSpace(c.RoutePrefix) ? "." : "..";
                c.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/v1/swagger.json", "v1");
                c.RoutePrefix = String.Empty;
            });

Does not work yet.

I have the following (using .net core 3.1 and trying to host on IIS) :

c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "API",
                    Version = "v1",
                    Description = "API"
                });

and

app.UseSwaggerUI(c =>
            {
                string swaggerJsonBasePath = string.IsNullOrWhiteSpace(c.RoutePrefix) ? "." : "..";
                c.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/v1/swagger.json", "v1");
                c.RoutePrefix = String.Empty;
            });

Does not work yet.

having the same problem on asp.net core 3.1.
It sais "Fetch errorNot Found /contoso/api/swagger/v1/swagger.json"

Hello. Try its:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        app.UseStaticFiles(new StaticFileOptions
        {
            FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "Swagger")),
            RequestPath = "/Swagger"
        });

        app.UseSwagger(options =>
        {
            options.RouteTemplate = "doc-api/{documentName}/swagger.json";
        });

        app.UseSwaggerUI(options =>
        {
            options.RoutePrefix = "doc-api";
            options.SwaggerEndpoint("v1/swagger.json", "Services API";
        });

    }

found the solution like this;

app.UseSwaggerUI(c =>
{
c.RoutePrefix = "myAppClient/swagger";
c.SwaggerEndpoint("/myAppClient/swagger/v1/swagger.json", "myApp Api Client");
});

Was this page helpful?
0 / 5 - 0 ratings

Related issues

qwertykeith picture qwertykeith  路  5Comments

niemyjski picture niemyjski  路  3Comments

DotNetRockStar picture DotNetRockStar  路  3Comments

calexandre picture calexandre  路  5Comments

guidoffm picture guidoffm  路  5Comments