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.Lazy
1.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.
Now the issue reproduced.
You can also reproduce the issue with combining conventional and attribute.
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.
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.