【问题标题】:ASP.NET MVC - Pass array object as a route value within Html.ActionLink(...)ASP.NET MVC - 将数组对象作为 Html.ActionLink(...) 中的路由值传递
【发布时间】:2010-10-17 14:10:27
【问题描述】:

我有一个返回数组 (string[]) 的方法,我正在尝试将这个字符串数组传递给 Action Link,以便它创建一个类似于以下内容的查询字符串:

/Controller/Action?str=val1&str=val2&str=val3...etc

但是当我通过 new { str = GetStringArray() } 我得到以下网址:

/Controller/Action?str=System.String%5B%5D

所以基本上它使用我的 string[] 并在其上运行 .ToString() 来获取值。

有什么想法吗?谢谢!

【问题讨论】:

  • 你有没有得到这个答案?

标签: asp.net-mvc arrays actionlink routes


【解决方案1】:

尝试创建一个 RouteValueDictionary 来保存您的值。您必须为每个条目指定一个不同的键。

<%  var rv = new RouteValueDictionary();
    var strings = GetStringArray();
    for (int i = 0; i < strings.Length; ++i)
    {
        rv["str[" + i + "]"] = strings[i];
    }
 %>

<%= Html.ActionLink( "Link", "Action", "Controller", rv, null ) %>

会给你一个类似的链接

<a href='/Controller/Action?str=val0&str=val1&...'>Link</a>

编辑:MVC2 更改了 ValueProvider 接口,使我原来的答案过时了。您应该使用具有字符串数组作为属性的模型。

public class Model
{
    public string Str[] { get; set; }
}

然后模型绑定器将使用您在 URL 中传递的值填充您的模型。

public ActionResult Action( Model model )
{
    var str0 = model.Str[0];
}

【讨论】:

  • 只是想我会提到,您似乎在此处为类似问题提供了另一种选择:[ASP.Net MVC RouteData and arrays] (stackoverflow.com/questions/1752721/…)。有没有办法将这两个问题联系起来,以便人们可以看到您的两种选择?
  • 我想你刚刚做到了。实际上,这将不再起作用。我将更新操作方法以使用模型。
  • 模型绑定不是问题。当 RouteValueDictionary 值包含数组/列表/等时,似乎 MVC 2 仍会生成像 ?str=System.String%5B%5D 这样的查询字符串。还是没有办法解决?
  • @Crescent - 你确定你使用的是既有路由值又有 html 属性的签名?
  • @tvanfosson:我相信是的。将new { foo = new[] { "a", "b" } } 之类的路由数据传递给Html.ActionLinkUrl.ActionHtmlHelper.GenerateLink 等中的任何一个都将生成一个类似?foo=System.String%5B%5D 的查询字符串参数,而不是预期的?foo=a&amp;foo=b。如果指定 html 属性会得到不同的结果吗?
【解决方案2】:

这真的让我很恼火,所以我用inspiration from Scott Hanselman 写了以下(流利的)扩展方法:

public static RedirectToRouteResult WithRouteValue(
    this RedirectToRouteResult result, 
    string key, 
    object value)
{
    if (value == null)
        throw new ArgumentException("value cannot be null");

    result.RouteValues.Add(key, value);

    return result;
}

public static RedirectToRouteResult WithRouteValue<T>(
    this RedirectToRouteResult result, 
    string key, 
    IEnumerable<T> values)
{
    if (result.RouteValues.Keys.Any(k => k.StartsWith(key + "[")))
        throw new ArgumentException("Key already exists in collection");

    if (values == null)
        throw new ArgumentNullException("values cannot be null");

    var valuesList = values.ToList();

    for (int i = 0; i < valuesList.Count; i++)
    {
        result.RouteValues.Add(String.Format("{0}[{1}]", key, i), valuesList[i]);
    }

    return result;
}

这样调用:

return this.RedirectToAction("Index", "Home")
           .WithRouteValue("id", 1)
           .WithRouteValue("list", new[] { 1, 2, 3 });

【讨论】:

    【解决方案3】:

    我想到的另一个解决方案:

    string url = "/Controller/Action?iVal=5&str=" + string.Join("&str=", strArray); 
    

    这很脏,您应该在使用它之前对其进行测试,但它仍然可以工作。希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      有一个名为Unbinder 的库,您可以使用它来将复杂的对象插入到路由/url 中。

      它是这样工作的:

      using Unbound;
      
      Unbinder u = new Unbinder();
      string url = Url.RouteUrl("routeName", new RouteValueDictionary(u.Unbind(YourComplexObject)));
      

      【讨论】:

        【解决方案5】:

        这是一个解决数组和 IEnumerable 属性问题的 HelperExtension:

        public static class AjaxHelperExtensions
        {
            public static MvcHtmlString ActionLinkWithCollectionModel(this AjaxHelper ajaxHelper, string linkText, string actionName, object model, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
            {
                var rv = new RouteValueDictionary();
        
                foreach (var property in model.GetType().GetProperties())
                {
                    if (typeof(ICollection).IsAssignableFrom(property.PropertyType))
                    {
                        var s = ((IEnumerable<object>)property.GetValue(model));
                        if (s != null && s.Any())
                        {
                            var values = s.Select(p => p.ToString()).Where(p => !string.IsNullOrEmpty(p)).ToList();
                            for (var i = 0; i < values.Count(); i++)
                                rv.Add(string.Concat(property.Name, "[", i, "]"), values[i]);
                        }
                    }
                    else
                    {
                        var value = property.GetGetMethod().Invoke(model, null) == null ? "" : property.GetGetMethod().Invoke(model, null).ToString();
                        if (!string.IsNullOrEmpty(value))
                            rv.Add(property.Name, value);
                    }
                }
                return System.Web.Mvc.Ajax.AjaxExtensions.ActionLink(ajaxHelper, linkText, actionName, rv, ajaxOptions, htmlAttributes);
            }
        }
        

        【讨论】:

          【解决方案6】:

          我将 POST 用于数组。除了丑陋和滥用 GET 之外,您还有 URL 空间不足的风险(信不信由你)。

          假设2000 byte limit。查询字符串开销 (&str=) 将您减少到大约 300 字节的实际数据(假设 url 的其余部分为 0 字节)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-03
            • 1970-01-01
            相关资源
            最近更新 更多