ASP.NET MVC - 清理复杂模型绑定场景中的 URL
在我正在构建的一个应用程序中,我构建了一个非常灵活的基于属性的系统,用于描述数据库中的产品,其中每个产品可以分配不确定数量的属性,每个属性都有一个“类型”。因此,例如,一种属性类型可能是“类别”,分配给单个属性的值可能类似于“卡车”。分配给给定产品的属性数量没有限制,并且由于属性和属性类型与产品一起存储在数据库中,因此我的应用程序提前不知道它们是什么。
给定属性类型的选项的特征之一是它是否是“可搜索的”。如果属性可搜索,我可以使用其值与其类型名称配对来搜索/过滤我的产品。因此,例如,用户可能想要返回属性类型“类别”等于“卡车”且属性类型“颜色”等于“红色”的所有产品。那里没有什么太独特的。
我遇到的麻烦是,因为我的系统事先不知道我的属性类型名称是什么,所以我无法轻松创建一个接受可读格式参数的操作方法,例如 stringcategory
或 字符串颜色
。作为解决方案,我利用了 DefaultModelBinder 对绑定到字典的支持。通过这种方法,我只需要以正确的结构格式化我的字段名称,然后我的操作方法就可以接受 IDictionary
<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>
这不仅非常冗长,而且还有些令人沮丧,因为每个键/值必须在字段名称中包含序数索引。虽然这对于 POST 表单来说是可以接受的,但在 GET URL 中并不是特别理想,因为我们最终得到的 URL 类似于 ?parameters[0].Key=Category¶meters[0].Value=Trucks¶meters[1 ].Key=制造商&参数[1].Value=福特
。这不仅丑陋,而且其实现也非常有限,因为对 URL 的任何修改都可能会破坏整个结果集(如果用户只想通过修改 URL 来按第二个参数进行搜索,则必须删除第一个参数并对整个集合进行适当的重新编号)。
我正在寻找一种更好的方法来处理这种情况。理想情况下,我只想有一个查询字符串值 ?Category=Red
并进行相应的过滤,但是我的操作方法不知道是否确实有要绑定的“类别”参数。两者之间是否有任何可以让我拥有更干净的查询字符串参数,而不会造成如此糟糕的 URL 结构?
我正在考虑是否可以构建自己的自定义 ModelBinder,但如果有其他方法,我想避免这种情况。
In one of the applications I am building I have constructed a very flexible attribute-based system for describing products in my database wherein each product can have an indeterminate number of attributes assigned to it with each attribute having a single "type". So, for example, one attribute type might be "Category" and the value assigned to a single attribute would be something like "Trucks". There are no restrictions on the number of attributes assigned to a given product and because the attributes and attribute types are stored in the database alongside the products, my application does not know ahead of time what any of them will be.
One of the features of the options for a given attribute type is whether or not it is "searchable". In the event of an attribute being searchable I can then use its value paired with its type name to search/filter my products. So, for example, a user might want to return all products having the attribute type "Category" equal "Trucks" and attribute type "Color" equal "Red". Nothing too unique there.
The trouble I am dealing with is that because my system does not know ahead of time what my attribute type names are, I cannot easily create an action method accepting parameters in a readable format like string category
or string color
. As a solution I have made use of the DefaultModelBinder's support for binding to a dictionary. With this approach I need only format my field names in the correct structure, and then my action method can accept an IDictionary<string,string> parameters
. This all works fairly well, but it makes for some really nasty URLs when the user is performing a link-based filter by a single parameter, i.e. "See more Products in Category Trucks". With the DefaultModelBinder binding to a dictionary requires that your field naming pattern resembles the following:
<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>
Not only is this incredibly verbose, but it also somewhat frustrating due to the fact that each Key/Value must contain an ordinal index in the field name. Although this is acceptable for a POST form, it is not particularly ideal in a GET URL because we end up with URLS resembling ?parameters[0].Key=Category¶meters[0].Value=Trucks¶meters[1].Key=Manufacturer¶meters[1].Value=Ford
. Not only is this ugly, it is very limited in its implementation because any modification to the URL could potential destroy the entire result set (if the user wanted to just search by the second parameter via modifying the URL they would have to remove the first parameter and renumber the whole collection appropriately).
What I am looking for is a better way to handle this kind of situation. Ideally I'd like to simply have a querystring value ?Category=Red
and filter accordingly, but then my action method doesn't know if there actually is a "Category" parameter to bind to. Is there any in between that would allow me to have cleaner querystring parameters that wouldn't make for such awful URL structures?
I was thinking about possibly building my own custom ModelBinder, but I'd like to avoid that if there's another way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我更喜欢你的“干净”URI:
?Category=Red
。那么让我们从这里开始,看看它是如何工作的。您可以在运行时加载所有类别,对吧?我突然想到:
您可以按原样使用它,或者制作一个自定义模型活页夹。无论哪种情况,代码都不是很多。
I much prefer your "clean" URIs:
?Category=Red
. So let's start there and see how it could work.You can load up all the categories at runtime, right? Off the top of my head:
You could use this as-is, or make a custom model binder. In either case, it's not a lot of code.