Configuring MapHttpAttributeRoutes for Web Api Versioning

I use the version of the API for web-API, both in web-API Version . My controllers are in two separate namespaces, and I used my own SelectController method to select which version to use based on the query parameter. eg

http://myapi/api/values?version=1.0

This all works fine, but some actions in the controllers use the Route attribute

[Route("api/values/getNames")]
public HttpResponseMessage Get() { ... }

which are mapped to the correct controller by default using

config.MapHttpAttributeRoutes();

in webapiconfig.cs

This will not work if I have multiple versions of the API with the same route. Can I provide a custom implementation for config.MapHttpAttributeRoutes () so that I can choose the right version of the API to use, or is there a better way to do this?

+4
2

WebApi 2.1 Codeplex. .

, , . , HTTP- ( ).

, ASP.NET Web API "api-version" HTTP-. , . , RouteFactoryAttribute (VersionedRoute) .

...

(VersionConstraint) "api-version" , . VersionedRoute, . , "api-version" . , , .

, :

[VersionedRoute("api/Customer", 1)]
public class CustomerVersion1Controller : ApiController
{
    // controller code goes here
}
[VersionedRoute("api/Customer", 2)]
public class CustomerVersion2Controller : ApiController
{
    // controller code goes here
}
+11

, - API 2 ( ) (.. , "api-version" querystring "api- = XXX".

HTTP- :

/// <summary>
/// Add a route constraint to detect version header or by query string
/// </summary>
public class RouteVersionHttpConstraint : IHttpRouteConstraint
{
    public const string VersionHeaderName = "api-version";
    private const int DefaultVersion = 1;
    /// <summary>
    /// Add a route constraint to detect version header or by query string
    /// </summary>
    /// <param name="allowedVersion"></param>
    public RouteVersionHttpConstraint(int allowedVersion)
    {
        AllowedVersion = allowedVersion;
    }

    public int AllowedVersion
    {
        get;
        private set;
    }

    /// <summary>
    /// Perform the controller match
    /// </summary>
    /// <param name="request"></param>
    /// <param name="route"></param>
    /// <param name="parameterName"></param>
    /// <param name="values"></param>
    /// <param name="routeDirection"></param>
    /// <returns></returns>
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        if (routeDirection == HttpRouteDirection.UriResolution)
        {
            int version = GetVersionHeaderOrQuery(request) ?? DefaultVersion;
            if (version == AllowedVersion)
            {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Check the request header, and the query string to determine if a version number has been provided
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    private int? GetVersionHeaderOrQuery(HttpRequestMessage request)
    {
        string versionAsString;
        IEnumerable<string> headerValues;
        if (request.Headers.TryGetValues(VersionHeaderName, out headerValues) && headerValues.Count() == 1)
        {
            versionAsString = headerValues.First();
            int version;
            if (versionAsString != null && Int32.TryParse(versionAsString, out version))
            {
                return version;
            }
        }
        else
        {
            var query = System.Web.HttpUtility.ParseQueryString(request.RequestUri.Query);
            string versionStr = query[VersionHeaderName];
            int version = 0;
            int.TryParse(versionStr, out version);
            if (version > 0)
                return version;
        }
        return null;
    }
}

factory:

/// <summary>
/// Versioning support for the WebAPI controllers
/// </summary>
public class RouteVersionAttribute : RouteFactoryAttribute
{
    public int Version { get; private set; }

    public RouteVersionAttribute() : this(null, 1) 
    { 
    }
    /// <summary>
    /// Specify a version for the WebAPI controller
    /// </summary>
    /// <param name="version"></param>
    public RouteVersionAttribute(int version) : this(null, version)
    {
    }

    public RouteVersionAttribute(string template, int version)
        : base(template)
    {
        Version = version;
    }

    public override IDictionary<string, object> Constraints
    {
        get
        {
            var constraints = new HttpRouteValueDictionary();
            constraints.Add("version", new RouteVersionHttpConstraint(Version));
            return constraints;
        }
    }

    public override IDictionary<string, object> Defaults
    {
        get
        {
            var defaults = new HttpRouteValueDictionary();
            defaults.Add("version", 1);
            return defaults;
        }
    }

}

:

[RouteVersion("api/versiontest", 1)]
public class Version1TestController : BaseApiController
{
    // get: api/versiontest
    [HttpGet]
    public HttpResponseMessage get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, new { Version = "API Version 1 selected" });
    }

}

[RouteVersion("api/versiontest", 2)]
public class Version2TestController : ApiController
{
    // get: api/versiontest
    [HttpGet]
    public HttpResponseMessage get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, new { Version = "API Version 2 selected" });
    }

}
+4

All Articles