Search code examples
c#asp.net-web-apiasp.net-web-api2api-versioning

Web-API Versioning not working with Default version


I created one web API application with versioning. I am going to use Microsoft.AspNet.WebApi.Versioning package to do that.

Webapi configuration:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.AddApiVersioning(o => {
            o.AssumeDefaultVersionWhenUnspecified = true;
        });
        // Web API routes
        config.MapHttpAttributeRoutes();

    }
}

Here my assumption is if I didn't pass the version, by default it will select version 1.

Controller code:

[ApiVersion("1.0")]
[RoutePrefix("api/users")]
public class UserV1Controller : BaseController
{
    public UserV1Controller()
    {
    }

    [Route("all", Name = "UsersCollection")]
    public async Task<IHttpActionResult> GetAll()
    {
        var items = await UnitOfWork.Users.GetPaged(x => x.OrderBy(y => y.Id), 1, 20);
        //Add mapping to DTO 
        return Ok(items);
    }

}

If I test with http://localhost:10280/api/users/all?api-version=1.0 URL, it working fine. I am going to implement this feature in the existing project.

For backward compatibility, I tried http://localhost:10280/api/users/all URL. It gives me the following error with 500 as the status code.

{ "Message": "An error has occurred.",
"ExceptionMessage": "The index cannot be less than 0 or equal to or larger than the number of items in the collection.\r\n
Parameter name: index\r\nActual value was 0.",
"ExceptionType": "System.ArgumentOutOfRangeException",
"StackTrace": " at
System.Web.Http.WebHost.Routing.HostedHttpRouteCollection.get_Item(Int32 index)\r\n at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.GetControllerName(HttpRequestMessage request)\r\n at Microsoft.Web.Http.Dispatcher.ControllerSelectionContext.<>c__DisplayClass6_0.<.ctor>b__0()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n
at Microsoft.Web.Http.Dispatcher.ConventionRouteControllerSelector.SelectController(ControllerSelectionContext context)\r\n at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.SelectController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__15.MoveNext()" }


Update 1:

After discussions and a bit of help, I can confirm that this default version works with conventional routing.

The issue reproduced while using attribute routing. Please check my updated code.

  1. I don't have any default API routing in the WebAPIConfig file.
  2. I update Route Prefix and Route in the controller

Now the issue reproduced.

You can also reproduce the issue with combining conventional and attribute.

Update 2:

Now I noticed that the issue lies in the configuration. If I add the routing configurations in the Owin startup class directly it working fine. 

    public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        var configuration = new System.Web.Http.HttpConfiguration();
        var httpServer = new System.Web.Http.HttpServer(configuration);

        // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
        configuration.AddApiVersioning(options =>
        {
            options.ReportApiVersions = true;
            options.AssumeDefaultVersionWhenUnspecified = true;
        });
        configuration.MapHttpAttributeRoutes();
        app.UseWebApi(httpServer);

    }
}

It creates new HttpConfiugration other than using our existing WebAPIConfig class. So I don't know it may impact any other functionalities

So if i configure Owin to use webaPI instead of GlobalConfiguration.Configure(WebApiConfig.Register) in the Global.asax, it iw working fine.


Solution

  • This is a confirmed bug that only occurs when hosting on a vanilla IIS implementation (e.g. non-OWIN). Despite the HttpRouteCollection having an indexer, the HostedHttpRouteCollection defined by System.Web does not support it. Instead of throwing NotSupportedException, a generic ArgumentOutOfRangeException is thrown.

    For more details see: https://github.com/Microsoft/aspnet-api-versioning/issues/428.

    The fix is in and is now available in package version 3.0.1.