ASP.NET MVC RouteValueDictionary и сложный объект - PullRequest
6 голосов
/ 20 декабря 2011

Каков наилучший способ сохранить результаты публикации формы (просмотр модели) на странице результатов поиска?

У меня есть форма поиска, которая содержит флажки. Эта форма создается с использованием модели вида, подобной

public class SearchViewModel
{
    public string Name { get; set; }
    public string[] Colors { get; set; }
}

Когда эта модель представления публикуется обратно, я использую значения для построения запроса (используя EF). Результаты превращаются в PagedList.

    public class SearchController : Controller
    {
    public ActionResult Index()
    {
        //this displays the search form.
        return View();
    }

    public ActionResult Results(string game, SearchViewModel vm)
    {
        //this displays the results
        ViewBag.SearchViewModel = vm;
        var matches = _repository.AsQueryable()
            .ColorOr(vm.Colors)
            .WhereIf(vm.Name.IsNotEmpty(), x => x.Name.Contains(vm.Name.Trim()));

            return View(matches.ToPagedList(1, 10));
    }
}

Теперь, когда отображаются результаты, я хотел бы использовать Html.PagedListPager и RouteValueDictionary для создания подкачки.

@Html.PagedListPager((IPagedList)Model, page => Url.Action("Results", new RouteValueDictionary(ViewBag.SearchViewModel)))

Тем не менее, созданный URL выглядит следующим образом:

http://localhost:5139/search?Name=test&Colors=System.String[]&PageIndex=0

Значения для Цветов в конечном итоге являются типом, а не значениями. Я надеялся, что URL будет выглядеть примерно так:

 http://localhost:5139/search?Name=test&Colors=[Blue,Pink,Yellow]&PageIndex=0
  1. Каков наилучший способ сохранения результатов публикации формы (просмотр модели) на странице результатов поиска?
  2. Может ли RouteValueDictionary поддерживать сложные объекты?
  3. Должен ли я использовать что-то вроде unbinder
  4. Мне лучше использовать ViewData или Session?

Ответы [ 2 ]

2 голосов
/ 21 декабря 2011

То, что я сделал для таких случаев, которые я нахожу простым, но мощным, сериализовало мой объект модели представления в JSON (в вашем случае SearchViewModel), используя что-то вроде NewtonSoft JSON.net затем с полученной строкой JSON выполните простое сжатие строки с помощью класса zlib.net Zlib.DeflateStream (вы также можете использовать что-то вроде AES Rijndael , но, несомненно, медленнее и вам нужна скорость в первую очередь), а затем передайте полученную строку Base64 через QueryString.

Затем, когда вы будете готовы использовать его снова (фактически это состояние представления), просто распакуйте строку JSON и десериализовайте ее из JSON в соответствующий объект .NET (снова в вашем случае SearchViewModel).

Сработал для меня, и вы не получите URL-адрес, который является неуправляемым, или каких-либо реальных ощутимых воздействий на производительность, которые я видел только при сериализации нескольких полей формы.

Я скоро уточню пример кода.

ОБНОВЛЕНИЕ: Примеры кода ...

Вот что я бы сделал в вашем конкретном сценарии:

В Results(string, SearchViewModel) действие:

public ActionResult Results(string encryptedUrlViewModel, string game, SearchViewModel vm)
{
    SearchViewModel searchUrlViewModel = null;
    if (!string.IsNullOrEmpty(searchUrl)) {
      // only first submission, no url view model set yet, so compress it and store..
      encryptedUrlViewModel = Convert.ToBase64String(
        DeflateStream.CompressString(JsonConvert.SerializeObject(vm)));
      ViewBag.EncryptedUrlViewModel = encryptedUrlViewModel;
    }
    else {
      var jsonUrlViewModel = DeflateStream.UncompressString(Convert.FromBase64String(encryptedUrlViewModel));
      searchUrlViewModel = JsonConvert.DeserializeObject(jsonUrlViewModel, typeof(SearchViewModel)) as SearchViewModel;
      // at this point you should have a serialized 'SearchViewModel' object 
      // ready to use which you can then tweak your query below with.
    }
    var matches = _repository.AsQueryable()
        .ColorOr(vm.Colors)
        .WhereIf(vm.Name.IsNotEmpty(), x => x.Name.Contains(vm.Name.Trim()));

    return View(matches.ToPagedList(1, 10));
}

На виду:

@Html.PagedListPager((IPagedList)Model, page => Url.Action("Results", new { encryptedUrlViewModel = ViewBag.EncryptedUrlViewModel }))

Код может потребовать некоторых настроек, непроверенных в вашем сценарии, но это будет что-то вроде этого, удачи:)

Однако вы должны подумать, что если вы хотите перенести запрос пользователя в URL через пейджинг, тогда можно подумать, почему форма не была создана как запрос GET, а не как запрос POST в первое место. По какой-то причине вы особенно хотели это POST? Я думаю, GET будет правильно переносить ваш массив Colors, но убедитесь, что ваша модель представления настроена правильно. См. Эту статью в Haacked для привязки модели к спискам .

1 голос
/ 11 февраля 2013

У меня была такая же проблема, но с параметрами поиска.У нас был параметр цвета, представляющий собой список имен цветов, которые использовала поисковая система.Таким образом, вы можете пометить черный и синий, и результат будет содержать как черный, так и синий продукты.

В итоге я использовал Unbound .

using Unbound;
Unbinder u = new Unbinder();

@Url.Action("Index", new RouteValueDictionary(u.Unbind(SearchParams)))

, что приводит к ссылкекак:

/MyRoute?color[0]=black&color[1]=blue
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...