代码之家  ›  专栏  ›  技术社区  ›  puffpio

ASP.NET MVC RouteData和数组

  •  24
  • puffpio  · 技术社区  · 15 年前

    如果我有这样的行为:

    public ActionResult DoStuff(List<string> stuff)
    {
       ...
       ViewData["stuff"] = stuff;
       ...
       return View();
    }
    

    我可以用以下网址点击:

    http://mymvcapp.com/controller/DoStuff?stuff=hello&stuff=world&stuff=foo&stuff=bar
    

    但在我的视图页面中,我有以下代码:

    <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = ViewData["stuff"] }, null) %>
    

    不幸的是,MVC不够聪明,无法识别该操作需要一个数组,并且展开列表以形成正确的URL路由。相反,它只对对象执行.toString(),该对象只在列表的情况下列出数据类型。

    当目标操作的参数之一是数组或列表时,是否有方法获取html.actionlink以生成正确的URL?

    --编辑--

    正如乔希在下面指出的,viewdata[“stufacture”]只是一个对象。我试图简化这个问题,但却导致了一个无关的错误!我实际上使用的是专用的viewpage<t>,所以我有一个紧密耦合的类型感知模型。actionLink实际上看起来像:

    <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = ViewData.Model.Stuff }, null) %>
    

    其中viewdata.model.stuff作为列表键入

    6 回复  |  直到 8 年前
        1
  •  20
  •   tvanfosson    14 年前

    我想定制的HTMLHelper应该是合适的。

     public static string ActionLinkWithList( this HtmlHelper helper, string text, string action, string controller, object routeData, object htmlAttributes )
     {
         var urlHelper = new UrlHelper( helper.ViewContext.RequestContext );
    
    
         string href = urlHelper.Action( action, controller );
    
         if (routeData != null)
         {
             RouteValueDictionary rv = new RouteValueDictionary( routeData );
             List<string> urlParameters = new List<string>();
             foreach (var key in rv.Keys)
             {
                 object value = rv[key];
                 if (value is IEnumerable && !(value is string))
                 {
                     int i = 0;
                     foreach (object val in (IEnumerable)value)
                     {
                         urlParameters.Add( string.Format( "{0}[{2}]={1}", key, val, i ));
                         ++i;
                     }
                 }
                 else if (value != null)
                 {
                     urlParameters.Add( string.Format( "{0}={1}", key, value ) );
                 }
             }
             string paramString = string.Join( "&", urlParameters.ToArray() ); // ToArray not needed in 4.0
             if (!string.IsNullOrEmpty( paramString ))
             {
                href += "?" + paramString;
             }
         }
    
         TagBuilder builder = new TagBuilder( "a" );
         builder.Attributes.Add("href",href);
         builder.MergeAttributes( new RouteValueDictionary( htmlAttributes ) );
         builder.SetInnerText( text );
         return builder.ToString( TagRenderMode.Normal );
    }
    
        2
  •  4
  •   Nerdroid    8 年前

    您可以在 routevalues 使用这样的数组索引:

    RouteValueDictionary rv = new RouteValueDictionary();
    rv.Add("test[0]", val1);
    rv.Add("test[1]", val2);
    

    这将导致包含 test=val1&test=val2

    那会有帮助吗?

        3
  •  3
  •   Nerdroid    8 年前

    两种方法结合起来很好。

    public static RouteValueDictionary FixListRouteDataValues(RouteValueDictionary routes)
    {
        var newRv = new RouteValueDictionary();
        foreach (var key in routes.Keys)
        {
            object value = routes[key];
            if (value is IEnumerable && !(value is string))
            {
                int index = 0;
                foreach (string val in (IEnumerable)value)
                {
                    newRv.Add(string.Format("{0}[{1}]", key, index), val);
                    index++;
                }
            }
            else
            {
                newRv.Add(key, value);
            }
        }
    
        return newRv;
    }
    

    然后在任何需要包含IEnumerable的RouteValues的扩展方法中使用此方法。

    可悲的是,MVC3也需要这种修井接缝。

        4
  •  0
  •   Krisztián Balla    11 年前

    有一个叫天秤座的 Unbinder ,可用于将复杂对象插入到路由/URL中。

    工作原理如下:

    using Unbound;
    
    Unbinder u = new Unbinder();
    string url = Url.RouteUrl("routeName", new RouteValueDictionary(u.Unbind(YourComplexObject)));
    
        5
  •  0
  •   tocsoft    8 年前

    这将作为对 UrlHelper 只需提供一个可以放在任何地方的好的URL,而不是一个完整的A标记,它还将为正在使用的任何其他特定URL保留大多数其他路由值…为您提供最友好的特定URL(减去IEnumerable值),然后在末尾附加查询字符串值。

    public static string ActionWithList(this UrlHelper helper, string action, object routeData)
    {
    
        RouteValueDictionary rv = new RouteValueDictionary(routeData);
    
        var newRv = new RouteValueDictionary();
        var arrayRv = new RouteValueDictionary();
        foreach (var kvp in rv)
        {
            var nrv = newRv;
            var val = kvp.Value;
            if (val is IEnumerable && !(val is string))
            {
                nrv = arrayRv;
            }
    
            nrv.Add(kvp.Key, val);
    
        }
    
    
        string href = helper.Action(action, newRv);
    
        foreach (var kvp in arrayRv)
        {
            IEnumerable lst = kvp.Value as IEnumerable;
            var key = kvp.Key;
            foreach (var val in lst)
            {
                href = href.AddQueryString(key, val);
            }
    
        }
        return href;
    }
    
    public static string AddQueryString(this string url, string name, object value)
    {
        url = url ?? "";
    
        char join = '?';
        if (url.Contains('?'))
            join = '&';
    
        return string.Concat(url, join, name, "=", HttpUtility.UrlEncode(value.ToString()));
    }   
    
        6
  •  -2
  •   Chaddeus    15 年前

    我不在我的工作站,但是像这样的事情怎么样:

    <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List<T>)ViewData["stuff"] }, null) %>
    

    或键入:

    <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List<T>)ViewData.Model.Stuff }, null) %>
    
    推荐文章