// 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;
}
}
}