Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

ApiVersionProperties set default to v1 #1082

Answered by xavierjohn
johnGeorge4 asked this question in Q&A
Discussion options

I'm trying to incorporate this package into an existing project in a way that would allow me to call my default APIs without using "v1" in my URL, and call the new versions using the api/v{apiVersion}/{controller}/{action} format.

I figure my best option would be to use AspNet/WebApi/ByNamespaceWebApiExample to get a working version so I know that I understand the concept correctly, but I get a 400 error when calling my test method because the API isn't being specified.

My POST call:
http://localhost:#/api/agreements/Hello

I'm using the following routes in my Startup.cs:

    configuration.Routes.MapHttpRoute(
        "Versioned2Url",
        "api/v{apiVersion}/{controller}/{action}",
        defaults: null,
        constraints: new { apiVersion = new ApiVersionRouteConstraint() } );

    configuration.Routes.MapHttpRoute( 
        "ActionApi", 
        "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });

and I've added a Route attribute to the V1 "Agreements" controller and created a simple method "Hello" that returns a string so I know if I hit the controller:

[Route( "api/Agreements" )]
public class AgreementsController : ApiController
{
[HttpPost]
public string Hello()
{
return "Hello v1";
}
}

I've also tried creating a "Controllers" folder located outside of any of the V1/V2/V3 folders and have created this same AgreementsController, but with the same result.

I found a suggestion online to add a case in the HttpControllerSelector method where if there is no version number being passed in the URL then to have the route default to the V1 route - I'd be open to trying this method, but when I look into the HttpControllerSelector method I'm not sure what I would need to do.

Any suggestions would be greatly appreciated!

You must be logged in to vote

Replies: 1 comment · 3 replies

Comment options

Looks similar to this issue

https://stackoverflow.com/questions/55416709/asp-net-core-set-default-api-versioning

You must be logged in to vote
3 replies
@johnGeorge4
Comment options

Thank you for the quick response! I wasn’t sure if something like that would work for my project since the one in that post is .net core and mine is .net, but I will give it a shot!

@johnGeorge4
Comment options

Ok, so it took a little tinkering but I was able to make the solution in the post that you provided work for my test project, thank you so much!

For anyone who has this same issue in the future, what worked for me was:

  • V1 Controller: add the Route[()] attribute:

namespace ApiVersioning.Examples.V1.Controllers;

using ApiVersioning.Examples.V1.Models;
using Asp.Versioning;
using System.Web.Http;

[Route( "api/v{version:apiVersion}/[controller]" )]
[Route( "api/[controller]" )]
[ApiVersion( "1.0" )]
public class AgreementsController : ApiController

{
.
.
.
}

  • Startup.cs:
    configuration.AddApiVersioning(
    options =>
    {
    options.ReportApiVersions = true;
    options.Conventions.Add( new VersionByNamespaceConvention() );
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion( 1, 0 );
    } );

      configuration.Routes.MapHttpRoute(
          "Versioned2Url",
          "api/v{apiVersion}/{controller}/{action}",
          defaults: null,
          constraints: new { apiVersion = new ApiVersionRouteConstraint() } );
    
      configuration.Routes.MapHttpRoute( 
          "ActionApi", 
          "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
    
      builder.UseWebApi( httpServer );
    

My V1 controller is still in the /V1/Controller folder - I'm going to do some testing to see if this also lets me use a controller that isn't in a "V#" folder so it can more easily be integrated into my existing project.

Thanks for the help @xavierjohn! I've been looking for a solution like this for what feels like weeks, turns out I just hadn't found the right post lol.

@commonsensesoftware
Comment options

This information and the correct configuration is in the wiki topic Known Limitations: URL Path Segment Routing. This includes the correct configuration for ASP.NET Core and ASP.NET Web API.

A few clarifying points:

  • be very careful changing the HttpControllerSelector service
    • this service is replaced by API Versioning
    • if it's not changed properly, things are very likely to break or not behave as expected
    • you should not need to customize or extend that service
  • you don't need to specify DefaultApiVersion; the default is already 1.0. it's not wrong, it's just unnecessary
  • if you're using VersionByNamespaceConvention, you shouldn't need [ApiVersion] on your controllers
    • the whole point is that the API version is derived by convention from the containing .NET namespace
    • if you have My.Api.V1.Controllers and [ApiVersion(1.0)], the same version is defined in 2 places
    • the API versions have to be distinct; the results are unioned and duplicates are ignored
    • if a controller has no API version applied by attribute or convention (including .NET namespace or folder), then the associated API version will be DefaultApiVersion with a default value of 1.0
  • it is strongly recommended that you do not mix and match direct routing (aka attribute-based routing) with convention-based routing; there be 🐉🐉🐉
    • there are route combinations that will not work; specifically for the same logical API
    • this is a limitation of the ASP.NET Web API routing system
    • it's recommended that you choose one routing method and stick to it
    • direct routing is typically easier to understand, debug, and will be closer to ASP.NET Core if/when you ever migrate
    • it was not mentioned, but if you are using OData, that is the one case where it's recommend that you stick with convention-based routing and only use that approach
      • OData only supports convention-based routing on ASP.NET Web API
Answer selected by johnGeorge4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
3 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.