iphonecoder777
iphonecoder777

Reputation: 51

Web API versioning configuration

I new in Mvc and try to write restful api, I use web api type of application, and try to create versioning, In final I would like to have link type like api/v1/values/get, api/v2/values/get. I tried to create folders v1 and v2 in controllers folder , and create there controllers with name ValuesController, but my request doesn't work. I got HTTP 404.0 - Not Found. How I can configure routing or do something to decide this problem?

Upvotes: 2

Views: 1665

Answers (3)

Chris Martinez
Chris Martinez

Reputation: 4438

If you need API Versioning in ASP.NET Web API, the Asp.Versioning.WebApi (formerly Microsoft.AspNet.WebApi.Versioning) provides a complete solution. You can version any way that you like:

  • By query (default)
  • By header
  • By media type
  • By URL segment
  • Custom
  • Any combination of options

Using the layout provided in the OP, the solution would be:

namespace Api.V1.Controllers
{
    [ApiVersion(1.0)]
    [RoutePrefix("api/v{version:apiVersion}/values")]
    public class ValuesController : ApiController
    {
        [HttpGet]
        [Route]
        public IHttpActionResult Get() =>
            Ok(new { message = "From V1" });
    }
}

namespace Api.V2.Controllers
{
    [ApiVersion(2.0)]
    [RoutePrefix("api/v{version:apiVersion}/values")]
    public class ValuesController : ApiController
    {
        [HttpGet]
        [Route]
        public IHttpActionResult Get() =>
            Ok(new { message = "From V2" });
    }
}

ApiVersion simply provides metadata to disambiguate routes. Using attributes tends to be the most common approach, but conventions are supported as well. There is even a built-in convention to derive an API version from the namespace .

public void Configuration(HttpConfiguration configuration)
{
    // we only need to change the default constraint resolver for services
    // that want urls with versioning like: ~/v{apiVersion}/{controller}
    var constraintResolver = new DefaultInlineConstraintResolver()
    { 
        ConstraintMap = { ["apiVersion"] = typeof( ApiVersionRouteConstraint ) },
    };

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

Upvotes: 0

mert
mert

Reputation: 2002

API versioning through namespace is explained here. Create a new HttpControllerSelector for yourself as described in the blog post and given example, then switch to that selector in your FilterConfig via:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));

Then, register your routes:

config.Routes.MapHttpRoute(
  name: "VersionedApi",
  routeTemplate: "api/{version}/{controller}/{id}",
  defaults: new { id = RouteParameter.Optional }
);

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = RouteParameter.Optional }
);

In your custom HttpControllerSelector, if you want to fallback to a default version, then use the following:

string versionName = GetRouteVariable<string>(routeData, "version");
versionName = versionName ?? DefaultVersion;

Upvotes: 3

Horizon_Net
Horizon_Net

Reputation: 5989

You can use attribute routing to achieve this kind of versioning. For your example it would look similar to the code snippet below

[RoutePrefix("api/v1/values")]
public class ValuesController : ApiController
{
  public object Get(int id) { ... }
}

[RoutePrefix("api/v2/values")]
public class NewValuesController : ApiController
{
  public object Get(int id) { ... }
}

Edit

Don't forget to enable attribute routing if you have an existing project. Your WebApiConfig should contain the following snippet:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Attribute routing.
    config.MapHttpAttributeRoutes();

    // Convention-based routing.
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
  }
}

You can delete the MapHttpRoute part if you don't want to use the convention-based configuration.

You should also make sure that your Global.asax contains the following:

protected void Application_Start()
{
  // Pass a delegate to the Configure method.
  GlobalConfiguration.Configure(WebApiConfig.Register);
}

Upvotes: 3

Related Questions