Вызов UrlHelper в моделях в ASP.NET MVC

159

Мне нужно создать несколько URL-адресов в модели в ASP.NET MVC. Я хотел бы вызвать что-то вроде UrlHelper.Action (), который использует маршруты для генерации URL. Я не против заполнить обычные пробелы, такие как имя хоста, схема и так далее.

Есть ли способ, который я могу вызвать для этого? Есть ли способ построить UrlHelper?

pupeno
источник
1
Я сам думал об этом, но учти, что Url.Action сгенерирует относительный URL. Будьте уверены, что это то, что вы хотите.
Река Вивиан

Ответы:

277

Полезный совет: в любом приложении ASP.NET вы можете получить ссылку на текущий HttpContext

HttpContext.Current

который получен из System.Web. Поэтому в любом месте приложения ASP.NET MVC будет работать следующее:

UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
url.Action("ContactUs"); // Will output the proper link according to routing info

Пример:

public class MyModel
{
    public int ID { get; private set; }
    public string Link
    {
        get
        {
            UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
            return url.Action("ViewAction", "MyModelController", new { id = this.ID });
        }
    }

    public MyModel(int id)
    {
        this.ID = id;
    }
}

Вызов Linkсвойства созданного объекта MyModel вернет действительный URL-адрес для просмотра модели на основе маршрутизации в Global.asax.

Омар
источник
Вы уверены, что есть HttpContext.Current.Request.RequestContext? HttpContext.Current.Request, похоже, не имеет RequestContext.
Пупено
1
Странно. Я только что проверил это решение, и оно отлично работает. Я использую ASP.NET MVC 2 Preview 2, но я думаю, что это работает во всех версиях. Не уверен, почему это не работает для вас. Вы создаете класс вне проекта MVC? Также убедитесь, что есть usingдля обоих System.WebиSystem.Web.Mvc
Омар
Я нахожусь на проекте ASP.NET MVC 1, я думал о пропущенном использовании, но у меня есть оба из них.
Пупено
Не совсем уверен, почему он не показывает. Если бы кто-то еще мог подтвердить, что это не существует в ASP.NET MVC 1, это было бы здорово. У меня только одна машина с VS2010 и MVC 2. Если вам интересно, MVC RC 2 haacked.com/archive/2009/12/16/aspnetmvc-2-rc.aspx
Омар
6
Обратите внимание, что Request.RequestContex поддерживается в .NET4 +
h - n
64

Мне нравится ответ Омара, но он не работает для меня. Для справки: вот решение, которое я использую сейчас:

var httpContext = HttpContext.Current;

if (httpContext == null) {
  var request = new HttpRequest("/", "http://example.com", "");
  var response = new HttpResponse(new StringWriter());
  httpContext = new HttpContext(request, response);
}

var httpContextBase = new HttpContextWrapper(httpContext);
var routeData = new RouteData();
var requestContext = new RequestContext(httpContextBase, routeData);

return new UrlHelper(requestContext);
pupeno
источник
Содержит URL моего сайта. Там я его убрал.
Пупено
4
Учитывая, что класс UrlHelper опирается на контекст запроса (и контекст HTTP), создание этих объектов контекста вручную может привести к неожиданным результатам. Если HttpContext.Current имеет значение null и вы используете этот подход, я буду действовать с осторожностью.
Шон
4
Остерегайтесь этого ответа - пустой объект RequestContext приводит к UrlHelper, который всегда возвращает пустую строку.
gknicker
47

UrlHelper может быть создан из действия Controller со следующим:

 var url = new UrlHelper(this.ControllerContext.RequestContext);
 url.Action(...);

За пределами контроллера UrlHelper может быть создан путем создания RequestContext из RouteTable.Routes RouteData.

HttpContextWrapper httpContextWrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
UrlHelper urlHelper = new UrlHelper(new RequestContext(httpContextWrapper, RouteTable.Routes.GetRouteData(httpContextWrapper)));

(Основано на ответе Брайана с добавлением незначительного исправления кода.)

Натан Тейлор
источник
2
Но у меня нет контроллера в модели.
Пупено
Хорошо, я прошу прощения, я не был уверен, где именно код выполнялся. Позвольте мне взглянуть ...
Натан Тейлор
2
Не нужно создавать новый контекст запроса:var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
bradlis7
Хороший @ bradlis7. Это MVC 5?
Натан Тейлор
1
Не работает, потому что this.ControllerContext.RequestContextесть HttpRequestContext, и конструктор UrlHelperожидает a RequestContext. Оба класса не связаны.
Флориан Зима
8

Да, вы можете создать его экземпляр. Вы можете сделать что-то вроде:

var ctx = new HttpContextWrapper(HttpContext.Current);
UrlHelper helper = new UrlHelper(
   new RequestContext(ctx,
   RouteTable.Routes.GetRouteData(ctx));

RouteTable.Routesявляется статическим свойством, поэтому вы должны быть в порядке; чтобы получить HttpContextBaseссылку, HttpContextWrapperберет ссылку HttpContextи HttpContextдоставляет это.

Брайан Майнс
источник
Это не будет работать, хотя это очень близко. Смотрите мой ответ ниже.
Натан Тейлор
3

Перепробовав все остальные ответы, я получил

$"/api/Things/Action/{id}"

Ненавистники будут ненавидеть ¯ \ _ (ツ) _ / ¯

Флориан Зима
источник
0

Я пытался сделать что-то подобное изнутри страницы (за пределами контроллера).

UrlHelper не позволил мне построить это так же легко, как Паблос, но потом я вспомнил старый трюк, чтобы эффективно сделать то же самое:

string ResolveUrl(string pathWithTilde)
vGHazard
источник
-30

Я думаю, что вы ищете это:

Url.Action("ActionName", "ControllerName");
user246874
источник