ASP.NET MVC RouteValueDictionary и сложный объект

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

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

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 ответов


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

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

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

Я уточнил с образцом кода в ближайшее время.

UPDATE: примеры кода...

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

на 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 для привязки модели к спискам.


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

Я закончил с помощью Unbound.

using Unbound;
Unbinder u = new Unbinder();

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

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

/MyRoute?color[0]=black&color[1]=blue