Question

Est-il possible d'obtenir une URL d'une action sans savoir ViewContext (par exemple, dans un contrôleur)? Quelque chose comme ceci:

LinkBuilder.BuildUrlFromExpression(ViewContext context, Expression<Action<T>> action)

... mais en utilisant Controller.RouteData au lieu de ViewContext. Il me semble avoir bloc métallique sur ce point.

Était-ce utile?

La solution

Voici comment je le fais dans un test unitaire:

    private string RouteValueDictionaryToUrl(RouteValueDictionary rvd)
    {
        var context = MvcMockHelpers.FakeHttpContext("~/");
        // _routes is a RouteCollection
        var vpd = _routes.GetVirtualPath(
            new RequestContext(context, _
                routes.GetRouteData(context)), rvd);
        return vpd.VirtualPath;
    }

Par commentaires, je vais adapter à un contrôleur:

string path = RouteTable.Routes.GetVirtualPath(
    new RequestContext(HttpContext, 
        RouteTable.Routes.GetRouteData(HttpContext)),
    new RouteValueDictionary( 
        new { controller = "Foo",
              action = "Bar" })).VirtualPath;

Remplacer "Foo" et "Bar" avec des noms réels. Ceci est du haut de ma tête, donc je ne peux garantir que c'est la solution la plus efficace possible, mais il vous devriez obtenir sur la bonne voie.

Autres conseils

Craig, Merci pour la réponse correcte. Il fonctionne très bien, et il va aussi me penser. Donc, dans mon lecteur pour éliminer ces refactor-cordes magiques « résistantes » j'ai développé une variante de votre solution:

public static string GetUrlFor<T>(this HttpContextBase c, Expression<Func<T, object>> action)
    where T : Controller
{
    return RouteTable.Routes.GetVirtualPath(
        new RequestContext(c, RouteTable.Routes.GetRouteData(c)), 
        GetRouteValuesFor(action)).VirtualPath;
}

public static RouteValueDictionary GetRouteValuesFor<T>(Expression<Func<T, object>> action) 
    where T : Controller
{
    var methodCallExpresion = ((MethodCallExpression) action.Body);
    var controllerTypeName = methodCallExpresion.Object.Type.Name;
    var routeValues = new RouteValueDictionary(new
    {
        controller = controllerTypeName.Remove(controllerTypeName.LastIndexOf("Controller")), 
        action = methodCallExpresion.Method.Name
    });
    var methodParameters = methodCallExpresion.Method.GetParameters();
    for (var i = 0; i < methodParameters.Length; i++)
    {
        var value = Expression.Lambda(methodCallExpresion.Arguments[i]).Compile().DynamicInvoke();
        var name = methodParameters[i].Name;
        routeValues.Add(name, value);
    }
    return routeValues;
}

Je sais ce que diront certains ... la réflexion redoutée! Dans mon application particulière, je pense que le bénéfice de la maintenabilité l'emporte sur conerns de performance. Je me réjouis des commentaires sur cette idée et le code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top