Skip to content

4 Troubleshooting and FAQ's

HelderSepu edited this page Jul 22, 2017 · 2 revisions
  1. Swagger-ui showing "Can't read swagger JSON from ..."
  2. Page not found when accessing the UI
  3. Swagger-ui broken by Visual Studio 2013
  4. OWIN Hosted in IIS - Incorrect VirtualPathRoot Handling
  5. How to add vendor extensions
  6. FromUri Query string DataMember names are incorrect
  7. Remove Duplicate Path Parameters
  8. Deploying behind Load Balancer / Reverse Proxies
  9. 500 : {"Message":"An error has occurred."}

Swagger-ui showing "Can't read swagger JSON from"

If you see this message, it means the swagger-ui received an unexpected response when requesting the Swagger document. You can troubleshoot further by navigating directly to the discovery URL included in the error message. This should provide more details.

If the discovery URL returns a 404 Not Found response, it may be due to a full-stop in the version name (e.g. "1.0"). This will cause IIS to treat it as a static file (i.e. with an extension) and bypass the URL Routing Module and therefore, Web API.

To workaround, you can update the version name specified in SwaggerConfig.cs. For example, to "v1", "1-0" etc. Alternatively, you can change the route template being used for the swagger docs (as shown here) so that the version parameter is not at the end of the route.

Page not found when accessing the UI

If you're using the SingleApiVersion, MultipleApiVersions or CustomAsset configuration settings you could still get this error. Check to ensure you're not specifying a value that causes a URL with an extension to be referenced in the UI. For example a full-stop in a version number ...

httpConfiguration
    .EnableSwagger(c => c.SingleApiVersion("1.0", "A title for your API"))
    .EnableSwaggerUi();

will result in a discovery URL like this "/swagger/docs/1.0" where the full-stop is treated as a file extension.

Swagger-ui broken by Visual Studio 2013

VS 2013 ships with a new feature - Browser Link - that improves the web development workflow by setting up a channel between the IDE and pages being previewed in a local browser. It does this by dynamically injecting JavaScript into your files.

Although this JavaScript SHOULD have no affect on your production code, it appears to be breaking the swagger-ui.

I hope to find a permanent fix, but in the meantime, you'll need to workaround this issue by disabling the feature in your web.config:

<appSettings>
    <add key="vs:EnableBrowserLink" value="false"/>
</appSettings>

OWIN Hosted in IIS - Incorrect VirtualPathRoot Handling

When you host Web API 2 on top of OWIN/SystemWeb, Swagger-Net cannot correctly resolve VirtualPathRoot by default.

You must either explicitly set VirtualPathRoot in your HttpConfiguration at startup, or perform customization like this to fix automatic discovery:

httpConfiguration.EnableSwagger(c => 
{
    c.RootUrl(req =>
        req.RequestUri.GetLeftPart(UriPartial.Authority) +
        req.GetRequestContext().VirtualPathRoot.TrimEnd('/'));
}

How to add vendor extensions

Swagger 2.0 allows additional meta-data (aka vendor extensions) to be added at various points in the Swagger document. Swagger-Net supports this by including a "vendorExtensions" dictionary with each of the extensible Swagger types. Meta-data can be added to these dictionaries from custom Schema, Operation or Document filters. For example:

public class ApplySchemaVendorExtensions : ISchemaFilter
{
    public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
    {
        schema.vendorExtensions.Add("x-foo", "bar");
    }
}

As per the specification, all extension properties should be prefixed by "x-"

FromUri Query string DataMember names are incorrect

When using FromUri Model Binding, it is possible to override the querystring parameter name's using DataMembers. In this case you can add a custom operation filter to override the name. For example:

public class ComplexTypeOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            return;

        var parameters = apiDescription.ActionDescriptor.GetParameters();
        foreach (var parameter in parameters)
        {
            foreach (var property in parameter.ParameterType.GetProperties())
            {
                var param = operation.parameters.FirstOrDefault(o => o.name.ToLowerInvariant().Contains(property.Name.ToLowerInvariant()));

                if (param == null) continue;

                var name = GetNameFromAttribute(property);

                if (string.IsNullOrEmpty(name))
                {
                    operation.parameters.Remove(param);
                }
                param.name = GetNameFromAttribute(property);
            }
        }
    }
    
    private static string GetNameFromAttribute(PropertyInfo property)
    {
        var customAttributes = property.GetCustomAttributes(typeof(DataMemberAttribute), true);
        if (customAttributes.Length > 0)
        {
            var attribute = customAttributes[0] as DataMemberAttribute;
            if (attribute != null) return attribute.Name;
        }
        return string.Empty;
    }
}

Remove Duplicate Path Parameters

When using FromUri Model Binding, duplicate items can appear as items can be passed as URI parameters, or querystrings. In this case you can add a custom operation filter to remove the duplicates. For example:

public class ComplexTypeOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
       if (operation.parameters == null)
           return;
       var complexParameters = operation.parameters.Where(x => x.@in == "query" && !string.IsNullOrWhiteSpace(x.name)).ToArray();

       foreach (var parameter in complexParameters)
       {
           if (!parameter.name.Contains('.')) continue;
           var name = parameter.name.Split('.')[1];

           var opParams = operation.parameters.Where(x => x.name == name);
           var parameters = opParams as Parameter[] ?? opParams.ToArray();

           if (parameters.Length > 0)
           {
               operation.parameters.Remove(parameter);
           }
       }
    }
}

Deploying behind Load Balancer / Reverse Proxies

Swagger-Net attempts to populate the Swagger "host" property from HTTP headers that are sent with the request for Swagger JSON. This may cause issues in load balancer / reverse proxy environments, particularly if non-standard headers are used to pass on the outer most host name. You can workaround this by providing your own function for determining your API's root URL based on vendor-specific headers.

500 : {"Message":"An error has occurred."}

If, on loading the Swagger UI page, you get an error: 500 : {"Message":"An error has occurred."} http://<url>/swagger/docs/v1 ensure that the XML documentation output settings have been set in the project file in the solution, for both Debug and Release configurations.