question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AssumeDefaultVersionWhenUnspecified is not working as expected

See original GitHub issue

I have been using asp net core versioning component for my WebAPI. Need your help in understanding how AssumeDefaultVersionWhenUnspecified is working. (tried searching for documentation, but couldn’t find one)

My startup looks like below

services.AddApiVersioning(o => {
            o.ReportApiVersions = true;
            o.AssumeDefaultVersionWhenUnspecified = true;
            o.DefaultApiVersion = new ApiVersion(2, 0);
            o.ApiVersionReader = new UrlSegmentApiVersionReader();
        });

When the route attribute is something like below

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/values")]
[ApiController]
public class ValuesV2Controller : ControllerBase
{
...
}

The above route works only when the api version is specified. ie: http://localhost:55401/api/v2/values If I call like http://localhost:55401/api/values, getting 404 error

My question is this. How AssumeDefaultVersionWhenUnspecified works. Wouldn’t it ignore the version in Route? Looks like Route attribute takes precedence over AssumeDefaultVersionWhenUnspecified. If I choose QueryString or Header versioning and when the Route looks like

[ApiVersion("2.0")]
[Route("api/values")]

the default routing reaches the API (when the version is not specified in the query string or header)

Am I missing anything or is my understanding wrong? How shall I achieve default routing to the latest version API using url versioning?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7

github_iconTop GitHub Comments

6reactions
commonsensesoftwarecommented, Sep 27, 2018

In short, you can’t. Since this style of versioning uses a URL segment, there is no way to omit part of the path. By definition of the Uniform Interface REST constraint, the path is the identifier so it doesn’t really make sense that you can default or omit part of it.

There is a way to make it work as explained here in the wiki. You will have to define multiple routes, effectively an alternate identiifer, where both routes map to the same action. One will have the API version in the path and the other will not. When the path without the API version is requested, the lack of an API version will be allowed and assumed to be the configured, default API version (as you have shown).

It also appears that you want to float this behavior to your latest version. Keep in mind that if you do that, you run the risk of breaking older clients because they won’t know they’ve been redirected to a nwe API version. Any API change, even additive, is not a guarantee that a client will not break. You will also have to move the route declaration without the API version segement to the latest controller implementation. You probably want to set the option:

options.ApiVersionSelector = new CurrentImplementationApiVersionSelector().

This will select the maximum API version (e.g. the current one) so that you don’t have to keep changing options.DefaultApiVersion which is used in several scenarios, not just for assuming the default version.

This limitation only applies to the URL segment method because it uses the path. All of the other supported versioning methods can support your requirements without having to do any other special setup.

I hope that helps.

3reactions
klucyszycommented, Oct 24, 2018

@commonsensesoftware Many thanks for your help! Now everything works great!

I’ve changed a little logic to be working with .NET Core. Now if the version is default swagger document do not show path with the version, else only paths with version are shown. Please find what the final solution, maybe someone will be interested.

using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace MyProject.Core.Extensions.Swagger
{
    public class DefaultApiVersionFilter : IDocumentFilter
    {
        private readonly IOptions<ApiExplorerOptions> _options;

        public DefaultApiVersionFilter(IOptions<ApiExplorerOptions> options)
        {
            _options = options;
        }

        protected ApiVersion DefaultApiVersion => _options.Value.DefaultApiVersion;
        protected string ApiVersionFormat => _options.Value.SubstitutionFormat;

        public void Apply(
            SwaggerDocument swaggerDoc,
            DocumentFilterContext context)
        {
            var versionSegment = DefaultApiVersion.ToString(ApiVersionFormat);

            foreach (var apiDescription in context.ApiDescriptions)
            {
                //If the version is default remove paths like: api/v1.0/controller
                if (apiDescription.GetApiVersion() == DefaultApiVersion)
                {
                    if (apiDescription.RelativePath.Contains(versionSegment))
                    {
                        var path = "/" + apiDescription.RelativePath;
                        swaggerDoc.Paths.Remove(path);
                    }
                }
                //If the version is not default remove paths like api/controller
                else
                {
                    var match = Regex.Match(apiDescription.RelativePath, @"^api\/v\d+");

                    if (!match.Success)
                    {
                        var path = "/" + apiDescription.RelativePath;
                        swaggerDoc.Paths.Remove(path);
                    }
                }
            }
        }
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

AssumeDefaultVersionWhenUns...
asp.net core - AssumeDefaultVersionWhenUnspecified is not working as expected - Stack Overflow.
Read more >
AssumeDefaultVersionWhenUns...
I've changed a little logic to be working with .NET Core. Now if the version is default swagger document do not show path...
Read more >
RESTful API versioning with ASP.NET Core
This blog post will discuss about the commonly used API Versioning strategies and how to implement them in ASP.NET Core Web API.
Read more >
API Versioning in ASP.net Core
The flag for “AssumeDefaultVersionWhenUnspecified” (Quite the mouthful), can also be handy especially when migrating an API to versioning.
Read more >
Your guide to REST API versioning in ASP.NET Core
This post describes how you can easily implement API versioning using ASP.NET Core libraries.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found