在ASP.NET MVC中,如何使用Html.ActionLink生成重复的名称('?v = 1& v = 2& v = 3')查询字符串

时间:2010-12-15 13:39:11

标签: c# asp.net-mvc

这不是关于如何将一系列复选框正确绑定到模型属性(一个常见问题)的问题 - 我的网站可以完美地读取请求中的复选框值,POST或GET +查询字符串。

这是关于如何使用Html.ActionLink生成在查询字符串中正确格式化多个复选框值的链接。

所以我有以下模型:

public class ModelType
{
    public string[] V { get; set; }
}

我在视图中为该模型绑定了3个复选框,因为我有三个可能的值(是的,是所述值的组合)。

这是最终的Html

<INPUT id="chk1" value="1" type="checkbox" name="V">
<INPUT id="chk2" value="2" type="checkbox" name="V">
<INPUT id="chk3" value="3" type="checkbox" name="V">

如果在将表单作为GET提交给服务器时检查了所有三个值,则生成的查询字符串当然是?V=1&V=2&V=3

模型绑定工作得很漂亮,一切都很愉快。

但是,假设我想生成指向同一操作的链接,传递匿名类型或RouteValueDictionary以生成相同的查询字符串;逻辑表明你会做这样的事情:

版本1:使用ModelType的实例作为视图上的模型:

<%= Html.ActionLink("Test link", null /* action name */, new { V = Model.V }) %>

版本2:将'V'成员直接初始化为数组:

<%= Html.ActionLink("Test link", null /* action name */,
    new { V = new string[] { "1", "2", "3" } }) %>

[在我问RouteValueDictionary的问题中,因为在这两种情况下,这两种匿名类型都会在链接生成发生之前变为这样。]

在这两种情况下,生成的查询字符串如下:?V=System.String%5B%5D

现在,我知道这是因为链接生成器只是在数组上调用ToString();但似乎没有办法向MVC传递一个会导致它生成?V=1&V=2&V=3的值。

由于这两种语言都不允许我们这样做:

new { V="1", V="2", ... }

也没有RouteValueDictionary允许我们这样做:

d["V"] = "1"; d["V"] = "2"; ...

我也尝试过预处理RouteValueDictionary的绝望措施,因此对于每个IEnumerable<string>,我生成一个字符串,每个值用逗号分隔,然后将该字符串写回 - 所以查询字符串的结尾如下:?V=1%2C2%2C3

但是当然MVC不会自动将这样的字符串绑定到一个数组(你只需要在数组中输入一个带逗号的字符串);因此,以这种方式绑定的每个属性都必须是自定义绑定的 - 对我来说,这似乎只是一些太多的箍要跳过。

所以我似乎陷入困境。

我错过了什么吗?我是否需要编写可以满足我想要的特殊版本的ActionLink?

任何帮助,一如既往,非常感谢。

2 个答案:

答案 0 :(得分:3)

所以我已经去研究了这个,这是我的看法。我希望有人可以提出一个更乐观的答案,但我想不出来。

完全遵循Html.ActionLink扩展方法,它产生的核心网址由(咳嗽)密封和(咳嗽咳嗽!)生成 内部 System.Web.Mvc.ParsedRoute以及Bind程序集中的方法System.Web.Routing

在此方法的最后(这是一个Reflector列表) - 这是它生成查询字符串的方式:

if (unusedNewValues.Count > 0)
{
    bool flag5 = true;
    foreach (string str2 in unusedNewValues)
    {
        object obj5;
        if (acceptedValues.TryGetValue(str2, out obj5))
        {
            builder.Append(flag5 ? '?' : '&');
            flag5 = false;
            builder.Append(Uri.EscapeDataString(str2));
            builder.Append('=');
            builder.Append(Uri.EscapeDataString(
              Convert.ToString(obj5, CultureInfo.InvariantCulture)));
        }
    }
}

我首先应该提到unusedNewValuesHashSet<string>,这意味着 - 不幸的是 - 它只会呈现 一个名称/值 配对

你不能用嵌入的a=b&a=c(...)字符串来捏造数据字符串,因为字符串值是转义的 - 因此除非你替换路由框架,否则根本不可能在Mvc中生成这样的查询字符串。

因此,另一种方法是编写一个集合数据类型,它类似于以下内容(这是一个脏实现):

public class StringCollection : List<string>
{
  public override string ToString()
  {
    //use the pipe character as a delimiter - but this doesn't work
    //if the strings being carried around ccould naturally contain '|'!
    return string.Join("|", this.ToArray());
  }
}

然后为首先使用默认方法的类型实现自定义模型绑定器(从DefaultModelBinder派生),然后检查生成的集合是否只有一个包含“|”的字符串其中的人物。如果是,则它对集合进行后处理,用单个字符串中的扩展值替换其内容。

这很可怕 - 但是我目前可以想到的所有解决方案中最不讨厌的。

刚才必须对我所有使用可能绑定到查询字符串值的字符串集合的现有模型类型进行一些更改...

答案 1 :(得分:1)

最近有类似的问题。我最终放弃了HtmlHelper / RouteValueDictionary并从头开始构建我的URL。类似的东西:

<a href="/Controller/Action?<%: string.Join("&", set.Select(i => "v=" + i))%>">Link</a>

可能不会吸引每个人的口味,但它对我有用。