2011-12-20 15 views
6

Qual è il metodo migliore per conservare i risultati di un modulo (modello di visualizzazione) nella pagina dei risultati di ricerca?ASP.NET MVC RouteValueDictionary e oggetto complesso

Ho un modulo di ricerca che contiene checkbox. Questa forma è costruire utilizzando un modello di vista come

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

Quando questo modello viene vista postback Io uso i valori per costruire una query (utilizzando EF). I risultati vengono trasformati in 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)); 
    } 
} 

Ora che i risultati vengono visualizzati Vorrei utilizzare Html.PagedListPager e RouteValueDictionary per creare paging.

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

Tuttavia; l'URL creato è simile al seguente:

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

I valori per Colori non sono il tipo. Speravo l'URL sembra più:

http://localhost:5139/search?Name=test&Colors=[Blue,Pink,Yellow]&PageIndex=0 
  1. Qual è il metodo migliore per mantenere i risultati di un post modulo (vista del modello) in tutta pagina dei risultati di ricerca?
  2. Can RouteValueDictionary può supportare oggetti complessi?
  3. Devo usare qualcosa come unbinder
  4. Sarebbe meglio usare ViewData o Session?
+0

Wow. Questa è la mia domanda esatta. +1 –

risposta

2

Quello che ho fatto per casi come questo, che trovo semplice, ma potente, è serializzato mio oggetto vista del modello di JSON (nel tuo caso SearchViewModel), usando qualcosa come NewtonSoft JSON.net poi con la stringa JSON risultante, eseguire una semplice compressione della stringa tramite la classe zlib.netZlib.DeflateStream (è inoltre possibile utilizzare qualcosa come AES Rijndael ma sarà senza dubbio più lenta e si desidera la velocità prima di tutto) e quindi passare la stringa Base64 risultante attraverso QueryString.

Quindi quando si è pronti a utilizzarlo nuovamente (è effettivamente un viewstate), è sufficiente decomprimere la stringa JSON e deserializzare da JSON nel rispettivo oggetto .NET (sempre nel proprio caso SearchViewModel).

Ha funzionato per me, e non si finisce con un URL che è ingestibile o impatti di prestazioni misurabili reali che ho visto con solo una manciata di campi modulo serializzati.

Elaborerò presto un esempio di codice.

AGGIORNAMENTO: Esempi di codice ...

Questo è quello che vorrei fare nella vostra situazione particolare:

In Results(string, SearchViewModel) azione:

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)); 
} 

In considerazione:

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

Il codice può richiedere alcune modifiche, non testati nel tuo scenario ma sarà qualcosa del genere, buona fortuna :)

Si dovrebbe prendere in considerazione, tuttavia, se si desidera portare la richiesta dell'utente nell'URL attraverso il paging, si potrebbe considerare il motivo per cui il modulo non è stato creato come una richiesta GET rispetto a una richiesta POST in primo luogo. Qualche ragione lo volevi particolarmente POST? Penso che GET porterà correttamente la matrice Colors, ma assicurati che il tuo modello di visualizzazione sia impostato correttamente. See this Haacked article for model binding to lists.

+0

Giusto per essere chiari. La soluzione più semplice, come detto sopra, era quella di cambiare il metodo del modulo da POST a GET. – detroitpro

+1

Haha .... doh. Oh, la mia mano ha elaborato una soluzione codificata da sprecare. Oh beh :) Potresti aver bisogno di qualcosa del genere un giorno .. =) – GONeale

+0

entrando in questo un po 'in ritardo, ma affrontando una simile sfida. Quindi dovresti avvolgere l'intero modulo di ricerca + lista dei risultati nel modulo Html per ottenere il corretto collegamento del modello? La parte di impaginazione del viewmodel di ricerca è se l'intera vista è nel modulo o è un argomento separato per l'azione del controller? –

1

Ho avuto lo stesso problema ma con i parametri di ricerca. Avevamo un parametro di colore che era un elenco di nomi di colori utilizzati dal motore di ricerca. Quindi puoi spuntare il nero e il blu e il risultato contiene nero e blu.

Ho finito per utilizzare Unbound.

using Unbound; 
Unbinder u = new Unbinder(); 

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

che si traduce in un link come:

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