// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Web.Http.Routing; using System.Web.Routing; namespace System.Web.Http.WebHost.Routing { /// /// Mimics the System.Web.Routing.Route class to work better for Web API scenarios. The only /// difference between the base class and this class is that this one will match only when /// a special "httproute" key is specified when generating URLs. There is no special behavior /// for incoming URLs. /// public class HttpWebRoute : Route { /// /// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API). /// If this key is not specified then no HTTP routes will match. /// private const string HttpRouteKey = "httproute"; [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")] public HttpWebRoute(string url, IRouteHandler routeHandler) : base(url, routeHandler) { } [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")] public HttpWebRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { } [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")] public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler) { } [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Matches the base class's parameter names.")] public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler) { } protected override bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { IHttpRouteConstraint httpRouteConstraint = constraint as IHttpRouteConstraint; if (httpRouteConstraint != null) { HttpRequestMessage request = httpContext.GetHttpRequestMessage(); if (request == null) { request = HttpControllerHandler.ConvertRequest(httpContext); httpContext.SetHttpRequestMessage(request); } return httpRouteConstraint.Match(request, new HostedHttpRoute(this), parameterName, values, ConvertRouteDirection(routeDirection)); } return base.ProcessConstraint(httpContext, constraint, parameterName, values, routeDirection); } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { // Only perform URL generation if the "httproute" key was specified. This allows these // routes to be ignored when a regular MVC app tries to generate URLs. Without this special // key an HTTP route used for Web API would normally take over almost all the routes in a // typical app. if (!values.ContainsKey(HttpRouteKey)) { return null; } // Remove the value from the collection so that it doesn't affect the generated URL RouteValueDictionary newValues = GetRouteDictionaryWithoutHttpRouteKey(values); return base.GetVirtualPath(requestContext, newValues); } private static RouteValueDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary routeValues) { var newRouteValues = new RouteValueDictionary(); foreach (var routeValue in routeValues) { if (!String.Equals(routeValue.Key, HttpRouteKey, StringComparison.OrdinalIgnoreCase)) { newRouteValues.Add(routeValue.Key, routeValue.Value); } } return newRouteValues; } private static HttpRouteDirection ConvertRouteDirection(RouteDirection routeDirection) { if (routeDirection == RouteDirection.IncomingRequest) { return HttpRouteDirection.UriResolution; } if (routeDirection == RouteDirection.UrlGeneration) { return HttpRouteDirection.UriGeneration; } throw Error.InvalidEnumArgument("routeDirection", (int)routeDirection, typeof(RouteDirection)); } } }