3

在我的 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>

在选中第一个和第三个复选框时,Querystring被序列化?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 的标准基础结构可以处理描述为输入的多键。是否没有标准的基础设施可以反过来处理它?我错过了什么吗?

4

4 回答 4

4

您可以通过以下方式执行此操作:

string url = Url.Action("DoFilter", TypeHelper2.ObjectToDictionary(filter) );

TypeHelper2.ObjectToDictionary是 .NET 内部方法的修改版本,可以在这两个文件 gist中找到。

改变的行为:当一个项目实现时IEnumerable,对于每个项目,都会在返回的字典中创建一个条目,并使用 as 键"Name[index]"(索引从 0 开始)。这是可能的,因为 MVC 控制器的绑定器可以同时处理tag=1&tag=3tag[0]=1&tag[1]=3查询字符串。

于 2015-02-12T16:31:15.143 回答
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;

  }
于 2015-02-12T16:44:51.930 回答
2

已对上述 2 个答案投了赞成票 - 它们都是非常好的答案。在这方面(重定向到操作或生成要重定向到的 URL)MVC 根本不“喜欢”数组。

我可以看到另外两种方法:

1)使用 TempData 持久化检索数组(例如在本文底部

2) 为 AdFilter 编写并使用自定义模型绑定器

我自己会选择后者 - 可测试且更具确定性(另外,当您进入服务器场场景时,我不知道 TempData 是如何工作的)

您可能要考虑的另一件事是使用诸如从 Index 操作返回的内容。

return View("DoFilter", new AdFilter(){tag = tag});

(这将返回 Dofilter 视图,同时在浏览器中保持 "index?tag[0]=1&tag 1 =2" url)

最后 - 感觉就像您采用过滤条件只是将它们发送回浏览器,以便浏览器可以再次询问过滤结果。也许更好的选择是将表单上的操作设置为从一开始就发布到“DoFilter”:

<form  method="post" action="DoFilter"> 

高温高压

于 2015-02-17T13:13:36.627 回答
1

您使用接受对象的重载Url.Action()来生成路由参数。在内部,这通过使用反射来构建每个属性名称及其.ToString()值的字典来工作。

在简单值类型的情况下,这可能是Name = "doekman"(变为/DoFilter?Name=doekman),但在属性是复杂对象或集合的情况下,它返回类型名(即.ToString()值)。没有进行递归,这是有道理的,因为查询字符串有长度限制,所以如果对复杂的对象和集合进行递归,如果集合包含很多项目,你很快就会超过限制并抛出异常(它会创建一个真正的丑陋的查询字符串)。

因此,How can this be done?除非您手动生成RouteValueDictionary(或编写自己的帮助程序来生成查询字符串),否则您不能

于 2015-02-18T11:19:50.770 回答