Appeler UrlHelper dans les modèles dans ASP.NET MVC


159

J'ai besoin de générer des URL dans un modèle dans ASP.NET MVC. Je voudrais appeler quelque chose comme UrlHelper.Action () qui utilise les routes pour générer l'URL. Cela ne me dérange pas de remplir les blancs habituels, comme le nom d'hôte, le schéma, etc.

Y a-t-il une méthode que je peux appeler pour cela? Existe-t-il un moyen de construire un UrlHelper?


1
J'y pensais moi-même, mais sachez que Url.Action générera une URL relative. Assurez-vous que c'est ce que vous voulez.
Vivian River

Réponses:


277

Conseil utile, dans n'importe quelle application ASP.NET, vous pouvez obtenir une référence du HttpContext actuel

HttpContext.Current

qui est dérivé de System.Web. Par conséquent, ce qui suit fonctionnera n'importe où dans une application ASP.NET MVC:

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

Exemple:

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

L'appel de la Linkpropriété sur un objet MyModel créé renverra l'URL valide pour afficher le modèle en fonction du routage dans Global.asax


Êtes-vous sûr qu'il existe un HttpContext.Current.Request.RequestContext? HttpContext.Current.Request ne semble pas avoir de RequestContext.
pupeno le

1
C'est étrange. Je viens de tester cette solution et cela fonctionne parfaitement. J'exécute ASP.NET MVC 2 Preview 2, mais je pense que cela fonctionne dans toutes les versions. Je ne sais pas pourquoi cela ne fonctionne pas pour vous. Créez-vous la classe en dehors d'un projet MVC? Assurez-vous également qu'il y en a usingpour les deux System.WebetSystem.Web.Mvc
Omar

Je suis sur un projet ASP.NET MVC 1, j'ai pensé à des utilisations manquantes mais j'ai les deux.
pupeno

Je ne sais pas vraiment pourquoi cela ne s'affiche pas. Si quelqu'un d'autre pouvait confirmer que cela n'existe pas dans ASP.NET MVC 1, ce serait formidable. Je n'ai qu'une seule machine avec VS2010 et MVC 2 installés. Si vous êtes intéressé, MVC RC 2 haacked.com/archive/2009/12/16/aspnetmvc-2-rc.aspx
Omar

6
Notez que Request.RequestContex est pris en charge dans .NET4 +
h - n

64

J'aime la réponse d'Omar mais cela ne fonctionne pas pour moi. Pour mémoire, c'est la solution que j'utilise actuellement:

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

Il contient l'URL de mon site. Là, je l'ai enlevé.
pupeno

4
Étant donné que la classe UrlHelper repose sur le contexte de la requête (et le contexte HTTP), la construction manuelle de ces objets de contexte peut produire des résultats inattendus. Si HttpContext.Current est nul et que vous utilisez cette approche, je procéderai avec prudence.
Sean

4
Méfiez-vous de cette réponse - le RequestContext fictif entraîne un UrlHelper qui renvoie toujours une chaîne vide.
gknicker

47

Un UrlHelper peut être construit à partir d'une action Controller avec les éléments suivants:

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

En dehors d'un contrôleur, un UrlHelper peut être construit en créant un RequestContext à partir de RouteTable.Routes RouteData.

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

(Basé sur la réponse de Brian, avec une correction de code mineure ajoutée.)


2
Mais je n'ai pas de contrôleur dans le modèle.
pupeno

D'accord, je m'excuse, je ne savais pas exactement où le code était exécuté. Laissez-moi jeter un oeil ...
Nathan Taylor

2
Pas besoin de créer un nouveau contexte de requête:var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
bradlis7

Bien @ bradlis7. Est-ce que c'est MVC 5?
Nathan Taylor

1
Ne fonctionne pas, car this.ControllerContext.RequestContextest a HttpRequestContext, et le constructeur de UrlHelperattend a RequestContext. Les deux classes ne sont pas liées.
Florian Winter

8

Oui, vous pouvez l'instancier. Vous pouvez faire quelque chose comme:

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

RouteTable.Routesest une propriété statique, vous devriez donc être OK; pour obtenir une HttpContextBaseréférence, HttpContextWrapperprend une référence HttpContextet la HttpContextdélivre.


Cela ne fonctionnera pas, même si c'est très proche. Voir ma réponse ci-dessous.
Nathan Taylor

3

Après avoir essayé toutes les autres réponses, j'ai fini avec

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

Les haineux vont détester ¯ \ _ (ツ) _ / ¯


0

J'essayais de faire quelque chose de similaire à partir d'une page (en dehors d'un contrôleur).

UrlHelper ne m'a pas permis de le construire aussi facilement que la réponse de Pablos, mais ensuite je me suis souvenu d'une vieille astuce pour faire efficacement la même chose:

string ResolveUrl(string pathWithTilde)

-30

Je pense que ce que vous recherchez est ceci:

Url.Action("ActionName", "ControllerName");
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.