Frage

Ist es möglich, eine URL aus einer Aktion zu bekommen, ohne zu wissen, Viewcontext (zum Beispiel in einem Controller)? So etwas wie folgt aus:

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

... aber mit Controller.RouteData statt Viewcontext. Ich scheine Metallblock auf diese zu haben.

War es hilfreich?

Lösung

Hier ist, wie ich es in einem Unit-Test zu tun:

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

Per Kommentare, ich an einen Controller anpassen werden:

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

Ersetzen "Foo" und "Bar" mit echten Namen. Dies ist aus der Spitze von meinem Kopf, so kann ich nicht garantieren, dass es die effizienteste Lösung möglich ist, aber es sollte man auf dem richtigen Weg zu bekommen.

Andere Tipps

Craig, Vielen Dank für die richtige Antwort. Es funktioniert großartig, und es geht ich auch zu denken. Also in meinem Laufwerk dieses Refactoring-resistent „magic strings“ Ich habe eine Variation auf Ihrer Lösung entwickelt habe, zu beseitigen:

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

Ich weiß, was einige sagen ... gefürchtete Reflexion! In meiner speziellen Anwendung, ich glaube, den Nutzen der Wartbarkeit überwiegt Leistung conerns. Ich begrüße jedes Feedback auf diese Idee und den Code.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top