Wywołaj UrlHelper w modelach w ASP.NET MVC

159

Muszę wygenerować adresy URL w modelu w ASP.NET MVC. Chciałbym wywołać coś takiego jak UrlHelper.Action (), który używa tras do wygenerowania adresu URL. Nie mam nic przeciwko wypełnianiu zwykłych spacji, takich jak nazwa hosta, schemat i tak dalej.

Czy jest jakaś metoda, której mogę użyć? Czy istnieje sposób na utworzenie UrlHelper?

pupeno
źródło
1
Sam o tym myślałem, ale pamiętaj, że Url.Action wygeneruje względny adres URL. Upewnij się, że tego chcesz.
Vivian River

Odpowiedzi:

277

Przydatna wskazówka: w dowolnej aplikacji ASP.NET można uzyskać odwołanie do bieżącego HttpContext

HttpContext.Current

który pochodzi z System.Web. W związku z tym następujące będą działać w dowolnym miejscu w aplikacji ASP.NET MVC:

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

Przykład:

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

Wywołanie Linkwłaściwości w utworzonym obiekcie MyModel zwróci prawidłowy adres URL, aby wyświetlić model na podstawie routingu w Global.asax

Omar
źródło
Czy na pewno istnieje HttpContext.Current.Request.RequestContext? HttpContext.Current.Request wydaje się nie mieć RequestContext.
pupeno
1
To dziwne. Właśnie przetestowałem to rozwiązanie i działa idealnie. Używam ASP.NET MVC 2 w wersji zapoznawczej 2, ale myślę, że to działa we wszystkich wersjach. Nie wiem, dlaczego to nie działa. Czy tworzysz klasę poza projektem MVC? Upewnij się również, że są usingdla obu System.WebiSystem.Web.Mvc
Omar
Jestem w projekcie ASP.NET MVC 1, myślałem o brakujących zastosowaniach, ale mam oba z nich.
pupeno
Nie bardzo wiem, dlaczego się nie wyświetla. Byłoby wspaniale, gdyby ktoś inny mógł potwierdzić, że to nie istnieje w ASP.NET MVC 1. Mam tylko jedną maszynę z zainstalowanym VS2010 i MVC 2. Jeśli jesteś zainteresowany, MVC RC 2 haacked.com/archive/2009/12/16/aspnetmvc-2-rc.aspx
Omar
6
Zwróć uwagę, że Request.RequestContex jest obsługiwany w .NET4 +
h - n
64

Podoba mi się odpowiedź Omara, ale to nie działa na mnie. Tak dla przypomnienia, oto rozwiązanie, którego teraz używam:

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
źródło
Zawiera adres URL mojej witryny. Tam go usunąłem.
pupeno
4
Biorąc pod uwagę, że klasa UrlHelper opiera się na kontekście żądania (i kontekście HTTP), ręczne tworzenie tych obiektów kontekstu może przynieść nieoczekiwane wyniki. Jeśli HttpContext.Current ma wartość null i używasz tego podejścia, postąpiłbym ostrożnie.
Sean
4
Uważaj na tę odpowiedź - dummied RequestContext skutkuje UrlHelper, który zawsze zwraca pusty ciąg.
gknicker
47

UrlHelper można skonstruować z poziomu akcji kontrolera z następującymi elementami:

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

Poza kontrolerem można skonstruować UrlHelper, tworząc RequestContext z RouteTable.Routes RouteData.

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

(Na podstawie odpowiedzi Briana, z dodaną niewielką poprawką kodu).

Nathan Taylor
źródło
2
Ale nie mam kontrolera w modelu.
pupeno
Okej, przepraszam, nie byłem pewien, gdzie dokładnie wykonywany jest kod. Pozwól mi spojrzeć ...
Nathan Taylor,
2
Nie ma potrzeby tworzenia nowego kontekstu żądania:var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
bradlis7
Nice @ bradlis7. Czy to MVC 5?
Nathan Taylor
1
Nie działa, ponieważ this.ControllerContext.RequestContextjest a HttpRequestContext, a konstruktor UrlHelperoczekuje a RequestContext. Obie klasy nie są ze sobą powiązane.
Florian Winter,
8

Tak, możesz go utworzyć. Możesz zrobić coś takiego:

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

RouteTable.Routesjest właściwością statyczną, więc powinno być OK; aby uzyskać HttpContextBaseodniesienie, HttpContextWrapperbierze je HttpContexti HttpContextdostarcza.

Brian Mains
źródło
To nie zadziała, chociaż jest bardzo blisko. Zobacz moją odpowiedź poniżej.
Nathan Taylor,
3

Po wypróbowaniu wszystkich innych odpowiedzi skończyłem

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

Hejterzy będą nienawidzić ¯ \ _ (ツ) _ / ¯

Florian Winter
źródło
0

Próbowałem zrobić coś podobnego z poziomu strony (poza kontrolerem).

UrlHelper nie pozwolił mi zbudować go tak łatwo, jak odpowiedź Pablosa, ale potem przypomniałem sobie stary trik, aby skutecznie zrobić to samo:

string ResolveUrl(string pathWithTilde)
vGHazard
źródło
-30

Myślę, że szukasz tego:

Url.Action("ActionName", "ControllerName");
user246874
źródło