在我的ASP.NET MVC 4应用程序中,我可以过滤多个标签。在HTML中,它看起来像这样:
<form>
<label>
<input type="checkbox" name="tag" value="1">One
</label>
<label>
<input type="checkbox" name="tag" value="2">Two
</label>
<label>
<input type="checkbox" name="tag" value="3">Three
</label>
<input type="submit" name="action" value="Filter">
</form>
当检查第一个和第三个复选框时,查询字符串被序列化为?tag=1&tag=3
,我的控制器很好地传递了具有以下类类型的对象:
// Filter class
public class Filter {
public ICollection<int> tag { get; set; }
}
// Controller method
public ActionResult Index(AdFilter filter)
{
string url = Url.Action("DoFilter", filter);
// url gets this value:
// "/controller/Index?tag=System.Collections.Generic.List%601%5BSystem.Int32%5D"
// I would expect this:
// "/controller/Index?tag=1&tag=3"
...
}
但是,对Url.Action
的调用会导致序列化集合的类型名称,而不是实际值。
如何做到这一点?
MVC的标准基础结构可以处理描述为输入的多键。是否没有标准的基础设施能够以相反的方式处理它?我错过了什么吗?
答案 0 :(得分:4)
您可以通过以下方式完成此操作:
string url = Url.Action("DoFilter", TypeHelper2.ObjectToDictionary(filter) );
TypeHelper2.ObjectToDictionary
是.NET内部方法的修改版本,可在此two file gist中找到。
更改行为:当项目实施IEnumerable
时,每个项目都有一个条目
在返回的字典中使用键"Name[index]"
创建(索引基于0)。这是可能的,因为MVC控制器的绑定器可以处理tag=1&tag=3
和tag[0]=1&tag[1]=3
个查询字符串。
答案 1 :(得分:3)
一个简单但不那么优雅的解决方案可以是:
public ActionResult Index(AdFilter filter)
{
string parameters = "?";
foreach (var item in filter.tag)
{
parameters += string.Format("tag={0}&", item);
}
//trimming the last "&"
parameters = parameters.TrimEnd(parameters[parameters.Length - 1]);
string url = Url.Action("DoFilter") + parameters;
}
答案 2 :(得分:2)
赞成以上2个答案 - 他们都是非常好的答案。在这方面(重定向到一个动作或生成一个URL重定向到)MVC根本不“喜欢”数组。
我可以看到两种进一步的方法:
1)使用TempData来持久检索数组(例如this article的底部)
2)为AdFilter编写和使用自定义模型绑定器
我自己会选择后者 - 可测试且更具确定性(另外,当您进入服务器场场景时,我不知道TempData如何工作)
您可能想要考虑的另一件事是使用类似于Index操作的返回。
return View("DoFilter", new AdFilter(){tag = tag});
(这将返回Dofilter视图,同时在浏览器中保持“index?tag [0] = 1&amp; tag 1 = 2”url)
最后 - 感觉您只是将过滤条件发送回浏览器,以便浏览器再次询问过滤结果。也许更好的选择是将表单上的操作设置为从一开始就发布到“DoFilter”:
<form method="post" action="DoFilter">
HTH
答案 3 :(得分:1)
您使用接受对象的Url.Action()
重载来生成路由参数。在内部,这通过使用反射来构建每个属性名称及其.ToString()
值的字典。
在简单值类型的情况下,这可能是Name = "doekman"
(变为/DoFilter?Name=doekman
),但在属性是复杂对象或集合的情况下,它返回类型名称(即.ToString()
值。没有进行递归,这是有道理的,因为查询字符串有长度限制,所以如果在复杂的对象和集合上进行递归,你很快就会超出限制并在集合包含大量项目时抛出异常(并且它会创建一个真正的丑陋的查询字符串)。
所以回答How can this be done?
除非你手动生成RouteValueDictionary
(或编写自己的助手来生成查询字符串),否则你不能这样做。