// 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; using System.Collections.Generic; using System.Diagnostics; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Routing; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc { /// /// An implementation of that contains methods to /// build URLs for ASP.NET MVC within an application. /// public class UrlHelper : IUrlHelper { private readonly IActionContextAccessor _actionContextAccessor; private readonly IActionSelector _actionSelector; /// /// Initializes a new instance of the class using the specified action context and /// action selector. /// /// The to access the action context /// of the current request. /// The to be used for verifying the correctness of /// supplied parameters for a route. /// public UrlHelper(IActionContextAccessor actionContextAccessor, IActionSelector actionSelector) { _actionContextAccessor = actionContextAccessor; _actionSelector = actionSelector; } protected IDictionary AmbientValues => ActionContext.RouteData.Values; protected ActionContext ActionContext => _actionContextAccessor.ActionContext; protected HttpContext HttpContext => ActionContext.HttpContext; protected IRouter Router => ActionContext.RouteData.Routers[0]; /// public virtual string Action(UrlActionContext actionContext) { var valuesDictionary = PropertyHelper.ObjectToDictionary(actionContext.Values); if (actionContext.Action != null) { valuesDictionary["action"] = actionContext.Action; } if (actionContext.Controller != null) { valuesDictionary["controller"] = actionContext.Controller; } var path = GeneratePathFromRoute(valuesDictionary); if (path == null) { return null; } return GenerateUrl(actionContext.Protocol, actionContext.Host, path, actionContext.Fragment); } /// public bool IsLocalUrl(string url) { return UrlUtility.IsLocalUrl(url); } /// public virtual string RouteUrl(UrlRouteContext routeContext) { var valuesDictionary = PropertyHelper.ObjectToDictionary(routeContext.Values); var path = GeneratePathFromRoute(routeContext.RouteName, valuesDictionary); if (path == null) { return null; } return GenerateUrl(routeContext.Protocol, routeContext.Host, path, routeContext.Fragment); } private string GeneratePathFromRoute(IDictionary values) { return GeneratePathFromRoute(routeName: null, values: values); } /// /// Generates the absolute path of the url for the specified route values by /// using the specified route name. /// /// The name of the route that is used to generate the URL. /// A dictionary that contains the parameters for a route. /// The absolute path of the URL. protected virtual string GeneratePathFromRoute(string routeName, IDictionary values) { var context = new VirtualPathContext(HttpContext, AmbientValues, values, routeName); var pathData = Router.GetVirtualPath(context); if (pathData == null) { return null; } // VirtualPathData.VirtualPath returns string.Empty for null. Debug.Assert(pathData.VirtualPath != null); var fullPath = HttpContext.Request.PathBase.Add(pathData.VirtualPath).Value; if (fullPath.Length == 0) { return "/"; } else { return fullPath; } } /// public virtual string Content(string contentPath) { if (string.IsNullOrEmpty(contentPath)) { return null; } else if (contentPath[0] == '~') { var segment = new PathString(contentPath.Substring(1)); var applicationPath = HttpContext.Request.PathBase; return applicationPath.Add(segment).Value; } return contentPath; } /// public virtual string Link(string routeName, object values) { return RouteUrl(new UrlRouteContext() { RouteName = routeName, Values = values, Protocol = HttpContext.Request.Scheme, Host = HttpContext.Request.Host.ToUriComponent() }); } private string GenerateUrl(string protocol, string host, string path, string fragment) { // We should have a robust and centrallized version of this code. See HttpAbstractions#28 Debug.Assert(path != null); var url = path; if (!string.IsNullOrEmpty(fragment)) { url += "#" + fragment; } if (string.IsNullOrEmpty(protocol) && string.IsNullOrEmpty(host)) { // We're returning a partial url (just path + query + fragment), but we still want it // to be rooted. if (!url.StartsWith("/", StringComparison.Ordinal)) { url = "/" + url; } return url; } else { protocol = string.IsNullOrEmpty(protocol) ? "http" : protocol; host = string.IsNullOrEmpty(host) ? HttpContext.Request.Host.Value : host; url = protocol + "://" + host + url; return url; } } } }