Aspnet-api-versioning: SwaggerDefaultValues throws NullReferenceException

Created on 24 Jan 2018  路  6Comments  路  Source: microsoft/aspnet-api-versioning

The SwaggerDefaultValues operation filter from your wiki throws a NullReferenceException.

if (parameter.Default == null)
{
    parameter.Default = description.RouteInfo.DefaultValue; // throws here
}

Because RouteInfo is null.

I applied it like this

services.AddSwaggerGen(c =>
{
    // rest omitted for brevity
    c.OperationFilter<SwaggerDefaultValues>();
}

Please advice

answered asp.net core enhancement question

Most helpful comment

FYI, there is a new version of the API Explorer package available. I've added an option called SubstituteApiVersionInUrl, which enables the behavior you want without further modification.

c# AddVersionedApiExplorer( options => options.SubstituteApiVersionInUrl = true );
The corresponding wiki topic and examples now reflect this too.

All 6 comments

Ah ... yes - I updated the code in the samples, but not the wiki. Thanks for catching that. I've updated the code examples in the wiki.

Theoretically, the RouteInfo should never be null. The only known case that I've found that can cause this is when you have a route parameter that is not formally bound to a model anywhere. For example, the {version:apiVersion} route parameter is usually not bound to any model and, therefore, there is no corresponding route information. The provided API Explorer knows how to handle this situation and builds the correct information for you. You may have other situations that the API Explorer doesn't know how to handle.

Adding a simple _null propagation_ should solve the problem for you:
description.RouteInfo?.DefaultValue;

I hope that helps.

It now runs :)

But is it supposed to have v{version} in the action title?

image

I mean it already know what version it's showing

image

Wouldn't it be better to remove the version parameter and just have /v2/Values?

This might seem _odd_, but it's the expected behavior. No part of API Versioning directly depends nor cares about Swagger/Swashbuckle. API Versioning does provide an API Explorer implementation that understands how to read and collate all of the defined APIs by API version. Swagger/Swashbuckle take a dependency on the API explorer (but not necessarily the one from API Versioning).

The reason this happens is because the API Explorer doesn't know (and shouldn't know) anything special about URLs or route templates. The path shown in the title is literally the relative path of the route template. You wouldn't expect the value of {id} to be filled in with a route template of api/v1/values/{id}. The {version} parameter is no different. The API Explorer does provide a default value so that a user doesn't have to specify a value; it will _just work_.

This behavior is an unfortunate consequence of versioning by a URL segment (which is arguably one more reason not to use that method). Some service authors don't like that. It's pretty easy to customize on your side. I recently provided an example of how to do this in #236.

Providing this support out-of-the-box has never been high on my priority list because it's pretty easy to customize and it's very specific to how Swagger/Swashbuckle or another tool wants to consume the information provided by the API Explorer. However, enough people have asked how to achieve this so I would entertain a feature enhancement to support it. I can't promise it will come anytime soon, but I'm willing to queue it up. It's not terribly difficult, but I have other priorities I'm currently working on.

I hope that helps.

Thank you for the explanation.

I found this handy SwashBuckle DocumentFilter that fixes the version path with just a few lines of code.
You probably already know about it.

public class SetVersionInPaths : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
    {
        swaggerDoc.Paths = swaggerDoc.Paths
            .ToDictionary(
                path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
                path => path.Value
            );
    }
}

FYI, there is a new version of the API Explorer package available. I've added an option called SubstituteApiVersionInUrl, which enables the behavior you want without further modification.

c# AddVersionedApiExplorer( options => options.SubstituteApiVersionInUrl = true );
The corresponding wiki topic and examples now reflect this too.

You're the man :)

Was this page helpful?
0 / 5 - 0 ratings