代码之家  ›  专栏  ›  技术社区  ›  Tim Scott

不带viewContext的URL表单操作

  •  3
  • Tim Scott  · 技术社区  · 16 年前

    是否可以在不知道viewContext的情况下(例如,在控制器中)从操作中获取URL?像这样:

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

    …但使用controller.routedata而不是viewContext。这上面好像有金属块。

    2 回复  |  直到 16 年前
        1
  •  5
  •   Pure.Krome    16 年前

    以下是我在单元测试中的方法:

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

    根据评论,我将适应一个控制器:

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

    用实名替换“foo”和“bar”。这超出了我的想象,所以我不能保证这是最有效的解决方案,但它会让你走上正确的道路。

        2
  •  4
  •   Tim Scott    16 年前

    克雷格,谢谢你的回答。它工作得很好,也让我开始思考。因此,为了消除那些抵制重构的“魔法字符串”,我在您的解决方案中开发了一个变体:

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

    我知道有些人会说什么…可怕的反思!在我的特定应用程序中,我认为可维护性的好处大于性能方面的好处。我欢迎任何关于这个想法和代码的反馈。