// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. 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.Controllers; using System.Web.Http.Properties; namespace System.Web.Http.Routing { /// /// Represents a factory for creating URLs. /// public class UrlHelper { private HttpRequestMessage _request; /// /// Initializes a new instance of the class. /// /// The default constructor is intended for use by unit testing only. public UrlHelper() { } /// /// Initializes a new instance of the class. /// /// The HTTP request message containing the context under which the URLs are generated. public UrlHelper(HttpRequestMessage request) { if (request == null) { throw Error.ArgumentNull("request"); } Request = request; } /// /// Gets the of the current . /// The setter is not intended to be used other than for unit testing purpose. /// public HttpRequestMessage Request { get { return _request; } set { if (value == null) { throw Error.PropertyNull(); } _request = value; } } /// /// Creates an absolute URL using the specified path. /// /// The URL path, which may be a relative URL, a rooted URL, or a virtual path. /// The generated URL. [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "It is safe to pass string here")] public virtual string Content(string path) { if (String.IsNullOrEmpty(path)) { throw Error.ArgumentNullOrEmpty("path"); } if (Request == null) { throw Error.InvalidOperation(SRResources.RequestIsNull, "UrlHelper"); } if (path.StartsWith("~/", StringComparison.Ordinal)) { // This is a virtual path, we need to combine it with the virtual path root string virtualPathRoot; HttpRequestContext requestContext = Request.GetRequestContext(); if (requestContext != null) { virtualPathRoot = requestContext.VirtualPathRoot; } else { HttpConfiguration configuration = Request.GetConfiguration(); if (configuration == null) { throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoConfiguration); } virtualPathRoot = configuration.VirtualPathRoot; } if (virtualPathRoot == null) { virtualPathRoot = "/"; } if (!virtualPathRoot.StartsWith("/", StringComparison.Ordinal)) { virtualPathRoot = "/" + virtualPathRoot; } if (!virtualPathRoot.EndsWith("/", StringComparison.Ordinal)) { virtualPathRoot += "/"; } return new Uri(Request.RequestUri, virtualPathRoot + path.Substring("~/".Length)).AbsoluteUri; } else { return new Uri(Request.RequestUri, path).AbsoluteUri; } } /// /// Creates a relative URL using the specified route and route data. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The generated URL. public virtual string Route(string routeName, object routeValues) { return Route(routeName, new HttpRouteValueDictionary(routeValues)); } /// /// Creates a relative URL using the specified route and route data. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The generated URL. public virtual string Route(string routeName, IDictionary routeValues) { return GetVirtualPath(Request, routeName, routeValues); } /// /// Creates an absolute URL using the given route and route data. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The generated URL. [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "It is safe to pass string here")] public virtual string Link(string routeName, object routeValues) { return Link(routeName, new HttpRouteValueDictionary(routeValues)); } /// /// Creates an absolute URL using the specified route and route data. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The generated URL. [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "It is safe to pass string here")] public virtual string Link(string routeName, IDictionary routeValues) { string link = Route(routeName, routeValues); if (!String.IsNullOrEmpty(link)) { link = new Uri(Request.RequestUri, link).AbsoluteUri; } return link; } private static string GetVirtualPath(HttpRequestMessage request, string routeName, IDictionary routeValues) { if (routeValues == null) { // If no route values were passed in at all we have to create a new dictionary // so that we can add the extra "httproute" key. routeValues = new HttpRouteValueDictionary(); routeValues.Add(HttpRoute.HttpRouteKey, true); } else { // Copy the dictionary so that we can guarantee that routeValues uses an OrdinalIgnoreCase comparer // and to add the extra "httproute" key used by all Web API routes to disambiguate them from other MVC routes. routeValues = new HttpRouteValueDictionary(routeValues); if (!routeValues.ContainsKey(HttpRoute.HttpRouteKey)) { routeValues.Add(HttpRoute.HttpRouteKey, true); } } HttpConfiguration configuration = request.GetConfiguration(); if (configuration == null) { throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoConfiguration); } IHttpVirtualPathData vpd = configuration.Routes.GetVirtualPath( request: request, name: routeName, values: routeValues); if (vpd == null) { return null; } return vpd.VirtualPath; } } }