Search code examples
c#asp.net-coreasp.net-core-webapiasp.net-core-3.1api-versioning

ASP.NET Core API Versioning - Same controller for all versions


I have an ASP.NET Core 3.1 API and I am introducing a new version for one of my controllers. I am using the Microsoft.AspNetCore.Mvc.Versioning NuGet package and I have set the new version to be the default version. All my other controllers should work with both the old version (1.0) and the new version (1.1).

For example:

    [ApiVersion("1.0", Deprecated = true)]
    public class MySampleController
    {
    }
    
    [ApiVersion("1.1")]
    public class MyNewSampleController
    {
    }

    [ApiVersion("1.0", Deprecated = true)]
    [ApiVersion("1.1")]
    public class AllOtherController
    {
    }

Questions:
Do I really have to add all versions to all controllers?
Is there a better/correct way of handling this?

I have tried to use [ApiVersionNeutral] but that does not seem correct and, according to the documentation, should only be used in special cases. If I do not add the [ApiVersion] attribute, it defaults to the new 1.1 version and 1.0 no longer works.

Since this is my first SO question, I hope itfalls within the guidelines :)


Solution

  • Q: Do I really have to add all versions to all controllers?

    A: Yes. API versions are discrete. A client should get exactly what they ask for and an appropriate error response if the server cannot satisfy the request.

    Q: Is there a better/correct way of handling this?

    A: There are several possible options. A better or more correct way of handling things is highly subjective. There are numerous factors and the final decision may simply come down to preference.

    A common misconception is that API Versioning uses attributes. It really doesn't care about attributes, it's just one possibility and one that tends to resonate with developers as metadata. You have the choice to use out-of-the-box attributes, custom attributes, out-of-the-box conventions, or your own custom conventions.

    The choice of how to apply the version metadata is typically of preference and practical management. A common scenario is to organize controllers in folders by API version. In several .NET languages, the folder name translates to part or all of the corresponding namespace. This arrangement is common enough that there is an out-of-the-box VersionByNamespaceConvention for it. For details, see the documentation. The By Namespace Sample also demonstrates how to up such a project end-to-end.

    API version-neutral means that an API takes any and all versions, including none at all. It can mean you don't care about the API version or that you accept a whole range that you'll deal with yourself. It is really only meant to be used with APIs that never change over time. For example, a HTTP DELETE operation typically does not change over time or across versions.

    It's not 100% clear what you mean by:

    "If I do not add the [ApiVersion] attribute, it defaults to the new 1.1 version and 1.0 no longer works."

    There are no defaults per se. This statement seems to imply that you have set the AssumeDefaultVersionWhenUnspecified option to true. You should not do that unless you have a very good reason to do so. That is probably one of the most abused features of API Versioning. A client must know the version it is asking for. Allowing a client to not specify a version and having things transition from 1.0 to 1.1 can break the client. The server can make no assumption that it won't. This feature was meant to grandfather in existing services that didn't previously have an explicit version defined. That scenario only exists when API Versioning is first enabled. As stated above, all controllers must have one or more discrete API versions, but the original set of APIs didn't have it explicitly defined. If this feature didn't exist, then the baseline set of clients that didn't know about an API version would break.