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?

pupeno
la source
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

Omar
la source
Ê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);
pupeno
la source
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.)

Nathan Taylor
la source
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.

Brian Mains
la source
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 ¯ \ _ (ツ) _ / ¯

Florian hiver
la source
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)
vGHazard
la source
-30

Je pense que ce que vous recherchez est ceci:

Url.Action("ActionName", "ControllerName");
user246874
la source