ASP.NET MVC - очистка URL-адресов в сценариях связывания сложной модели - PullRequest
0 голосов
/ 14 июля 2010

В одном из приложений, которые я создаю, я создал очень гибкую систему атрибутов для описания продуктов в моей базе данных, в которой каждому продукту может быть присвоено неопределенное количество атрибутов, причем каждый атрибут имеет один «тип».Так, например, один тип атрибута может быть «Категория», а значение, назначенное для одного атрибута, будет что-то вроде «Грузовики».Нет ограничений на количество атрибутов, назначенных данному продукту, и поскольку атрибуты и типы атрибутов хранятся в базе данных вместе с продуктами, мое приложение заранее не знает, каким из них будет.

Одной из особенностей опций для данного типа атрибута является то, является ли он «доступным для поиска».Если атрибут доступен для поиска, я могу использовать его значение в паре с именем типа для поиска / фильтрации моих товаров.Так, например, пользователь может захотеть вернуть все товары, имеющие тип атрибута «Категория», равный «Грузовики» и тип атрибута «Цвет», равный «Красный».Ничего особенного там нет.

Проблема, с которой я сталкиваюсь, заключается в том, что, поскольку моя система не знает заранее, каковы имена типов моих атрибутов, я не могу легко создать метод действия, принимающий параметры в читаемом формате, таком как string category или string color.В качестве решения я использовал поддержку DefaultModelBinder для привязки к словарю.При таком подходе мне нужно только отформатировать имена моих полей в правильной структуре, и тогда мой метод действия может принять IDictionary<string,string> parameters.Это все работает довольно хорошо, но это делает некоторые действительно неприятные URL-адреса, когда пользователь выполняет фильтр на основе ссылок по одному параметру, то есть «Посмотреть больше продуктов в категории грузовиков».С привязкой DefaultModelBinder к словарю требуется, чтобы ваш шаблон именования полей был похож на следующее:

<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&parameters[0].Value=Trucks&parameters[1].Key=Manufacturer&parameters[1].Value=Ford.Это не только уродливо, но и очень ограничено в своей реализации, поскольку любая модификация URL может потенциально уничтожить весь набор результатов (если пользователь хочет просто выполнить поиск по второму параметру, изменив URL, ему придется удалить первый параметр).и соответствующим образом изменить нумерацию всей коллекции.

То, что я ищу, - лучший способ справиться с подобной ситуацией.В идеале я хотел бы просто иметь значение строки запроса ?Category=Red и соответственно фильтровать, но тогда мой метод действия не знает, существует ли на самом деле параметр «Категория», к которому нужно привязаться.Есть ли что-то среднее, что позволило бы мне иметь более чистые параметры строки запроса, которые не создавали бы для таких ужасных структур URL?

Я думал о возможном создании своего собственного ModelBinder, но я бы хотел этого избежатьесли есть другой способ.

1 Ответ

2 голосов
/ 14 июля 2010

Я предпочитаю ваши "чистые" 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]
             };

Вы можете использовать это как есть или создать пользовательский переплет модели. В любом случае, это не много кода.

...