Получение полного URL-адреса действия в ASP.NET MVC

Есть ли встроенный способ получения полного URL-адреса действия?

Я ищу что-то вроде GetFullUrl("Action", "Controller"), которое вернет что-то вроде http://www.fred.com/Controller/Action.

Причина, по которой я ищу это, заключается в том, чтобы избежать URL-адресов жесткого кодирования в автоматических электронных письмах, которые генерируются, чтобы URL-адреса всегда могли быть сгенерированы относительно текущего местоположения сайта.

Ответ 1

Существует перегрузка Url.Action, которая принимает ваш желаемый протокол (например, http, https) в качестве аргумента. Если вы укажете это, вы получите полный URL-адрес.

Вот пример, который использует протокол текущего запроса в методе действий:

var fullUrl = this.Url.Action("Edit", "Posts", new { id = 5 }, this.Request.Url.Scheme);

HtmlHelper (@Html) также имеет перегрузку метода ActionLink, который можно использовать в бритве для создания элемента привязки, но для этого также требуются параметры hostName и фрагмента. Поэтому я просто решил снова использовать @Url.Action:

<span>
  Copy
  <a href='@Url.Action("About", "Home", null, Request.Url.Scheme)'>this link</a> 
  and post it anywhere on the internet!
</span>

Ответ 2

Как сказал Пэдди: , если вы используете перегрузку UrlHelper.Action(), которая явно указывает используемый протокол, сгенерированный URL будет абсолютным и полностью квалифицированным, а не относительным.

Я написал сообщение в блоге Как создать URL абсолютного действия с использованием класса UrlHelper, в котором я предлагаю написать собственный метод расширения для ради удобочитаемости:

/// <summary>
/// Generates a fully qualified URL to an action method by using
/// the specified action name, controller name and route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
public static string AbsoluteAction(this UrlHelper url,
    string actionName, string controllerName, object routeValues = null)
{
    string scheme = url.RequestContext.HttpContext.Request.Url.Scheme;

    return url.Action(actionName, controllerName, routeValues, scheme);
}

Затем вы можете просто использовать его в своем представлении:

@Url.AbsoluteAction("Action", "Controller")

Ответ 3

Это то, что вам нужно сделать.

@Url.Action(action,controller, null, Request.Url.Scheme)

Ответ 4

Этот вопрос специфичен для ASP.NET, однако я уверен, что некоторые из вас принесут пользу системному агностическому javascript, который выгоден во многих ситуациях.

ОБНОВЛЕНИЕ:. Способ получения url, сформированного за пределами самой страницы, хорошо описан в ответах выше.

Или вы можете сделать oneliner следующим образом:

new UrlHelper(actionExecutingContext.RequestContext).Action(
    "SessionTimeout", "Home", 
    new {area = string.Empty}, 
    actionExecutingContext.Request.Url!= null? 
    actionExecutingContext.Request.Url.Scheme : "http"
);

из фильтра или:

new UrlHelper(this.Request.RequestContext).Action(
    "Details", 
    "Journey", 
    new { area = productType }, 
    this.Request.Url!= null? this.Request.Url.Scheme : "http"
);

Однако довольно часто нужно получить URL-адрес текущей страницы, для тех случаев, когда используется Html.Action, и ставить имя и контроллер страницы, в которой вы находитесь, мне неловко. В таких случаях я предпочитаю использовать JavaScript. Это особенно хорошо в системах, которые наполовину переписаны MVT половину веб-форм, половина vb- script половина, которую знает Бог, - и для получения URL-адреса текущей страницы каждый раз нужно использовать разные методы.

Один из способов - использовать JavaScript для получения URL-адреса window.location.href другой - document.URL

Ответ 5

Это может быть только я, действительно, действительно придирчивый, но мне нравится определять константы только один раз. Если вы используете какой-либо из подходов, определенных выше, ваша константа действия будет определяться несколько раз.

Чтобы этого избежать, вы можете сделать следующее:

    public class Url
    {
        public string LocalUrl { get; }

        public Url(string localUrl)
        {
            LocalUrl = localUrl;
        }

        public override string ToString()
        {
            return LocalUrl;
        }
    }

    public abstract class Controller
    {
        public Url RootAction => new Url(GetUrl());

        protected abstract string Root { get; }

        public Url BuildAction(string actionName)
        {
            var localUrl = GetUrl() + "/" + actionName;
            return new Url(localUrl);
        }

        private string GetUrl()
        {
            if (Root == "")
            {
                return "";
            }

            return "/" + Root;
        }

        public override string ToString()
        {
            return GetUrl();
        }
    }

Затем создайте свои контроллеры, например, DataController:

    public static readonly DataController Data = new DataController();
    public class DataController : Controller
    {
        public const string DogAction = "dog";
        public const string CatAction = "cat";
        public const string TurtleAction = "turtle";

        protected override string Root => "data";

        public Url Dog => BuildAction(DogAction);
        public Url Cat => BuildAction(CatAction);
        public Url Turtle => BuildAction(TurtleAction);
    }

Затем просто используйте его как:

    // GET: Data/Cat
    [ActionName(ControllerRoutes.DataController.CatAction)]
    public ActionResult Etisys()
    {
        return View();
    }

И из вашего .cshtml(или любого кода)

<ul>
    <li><a href="@ControllerRoutes.Data.Dog">Dog</a></li>
    <li><a href="@ControllerRoutes.Data.Cat">Cat</a></li>
</ul>

Это определенно намного больше работы, но я спокойно понимаю, что проверка времени компиляции на моей стороне.

Ответ 6

У меня возникла проблема с этим, мой сервер работал за балансировщиком нагрузки. Балансировщик нагрузки завершил соединение SSL/TLS. Затем он передал запрос веб-серверам с помощью http.

Используя метод Url.Action() с Request.Url.Schema, он продолжал создавать URL-адрес http, в моем случае для создания ссылки в автоматическом электронном письме (который мне не понравился PenTester).

Возможно, я немного обманул, но это именно то, что мне нужно было для создания https-url:

<a href="@Url.Action("Action", "Controller", new { id = Model.Id }, "https")">Click Here</a>

Я действительно использую AppSetting для web.config, поэтому я могу использовать http при локальном отладке, но во всех средах тестирования и prod используется преобразование для установки значения https.