ASP.NET MVC - 在复杂模型绑定方案中清理URL

时间:2010-07-14 17:30:09

标签: asp.net-mvc model-binding

在我正在构建的一个应用程序中,我构建了一个非常灵活的基于属性的系统,用于描述我的数据库中的产品,其中每个产品可以具有分配给它的不确定数量的属性,每个属性具有单个“类型”。因此,例如,一个属性类型可能是“类别”,分配给单个属性的值将类似于“卡车”。分配给给定产品的属性数量没有限制,因为属性和属性类型与产品一起存储在数据库中,我的应用程序不会提前知道它们是什么。

给定属性类型的选项的一个特征是它是否是“可搜索的”。如果属性可搜索,我可以使用其值与其类型名称配对来搜索/过滤我的产品。因此,例如,用户可能想要返回属性类型“Category”等于“Trucks”且属性类型“Color”等于“Red”的所有产品。那里没什么特别的。

我正在处理的问题是因为我的系统提前不知道我的属性类型名称是什么,所以我不能轻易地创建一个以可读格式接受参数的操作方法,如string category或{{1 }}。作为一种解决方案,我已经使用DefaultModelBinder支持绑定到字典。使用这种方法,我只需要在正确的结构中格式化我的字段名称,然后我的操作方法可以接受string color。这一切都运行得很好,但是当用户通过单个参数执行基于链接的过滤器时,它会产生一些非常讨厌的URL,即“查看类别卡车中的更多产品”。使用DefaultModelBinder绑定到字典需要您的字段命名模式类似于以下内容:

IDictionary<string,string> parameters

这不仅令人难以置信的冗长,而且由于每个Key / Value必须在字段名称中包含序数索引,因此它也有点令人沮丧。虽然这对于POST表单是可以接受的,但在GET URL中并不是特别理想,因为我们最终得到的URL类似于<input type="hidden" name="parameters[0].Key" value="Category" /> <select name="parameters[0].Value"> <option value="Trucks">Trucks</option> <option value="Compacts">Compacts</option> <option value="SUVs">SUVs</option> </select> <input type="hidden" name="parameters[1].Key" value="Manufacturer" /> <select name="parameters[1].Value"> <option value="Ford">Ford</option> <option value="Toyota">Toyota</option> <option value="Honda">Honda</option> </select> 。这不仅是丑陋的,它的实现非常有限,因为对URL的任何修改都可能破坏整个结果集(如果用户想要通过修改URL来搜索第二个参数,则必须删除第一个参数并适当地重新整理整个系列。)

我正在寻找的是处理这种情况的更好方法。理想情况下,我想简单地使用查询字符串值?parameters[0].Key=Category&parameters[0].Value=Trucks&parameters[1].Key=Manufacturer&parameters[1].Value=Ford并相应地进行过滤,但是我的操作方法不知道是否确实存在要绑定的“类别”参数。是否有任何介于两者之间会有更清晰的查询字符串参数,而这些参数不会产生如此糟糕的URL结构?

我正在考虑建立自己的自定义ModelBinder,但如果还有其他方法,我想避免这种情况。

1 个答案:

答案 0 :(得分:2)

我更喜欢你的“干净”URI:?Category=Red。所以,让我们从那里开始,看看它是如何运作的。

您可以在运行时加载所有类别,对吧?在我的头顶:

IEnumerable<string> allCategories = Categories.GetAll();
var usedCategories = Request.QueryString.AllKeys.Intersect(allCategories);
var search = from c in usedCategories
             select new 
             {
                 Key = c,
                 Value = Request.QueryString[c]
             };

您可以按原样使用它,也可以制作自定义模型装订器。在任何一种情况下,它都不是很多代码。