Domanda

La mia non familiarità con il framework ASP.NET MVC e il suo impianto idraulico mi ha portato qui, e apprezzo la pazienza che ci vorrà affinché chiunque legga e consideri la mia domanda!

Ok, ecco lo scenario: ho un'applicazione che ha numerose pagine con griglie che visualizzano dati basati su ricerche, il drill down da altri dati, report basati su dati specifici del contesto (cioè sono su una pagina di dettagli per Foo , quindi fai clic su un link che mostra una tabella di dati relativi a Foo), ecc.

Da una qualsiasi di queste pagine, che si trovano in tutta l'app, l'utente può salvare il "report" o griglia assegnandogli un nome e una descrizione. Questo in realtà non salva i dati, visualizzati nella griglia, tanto quanto salva i parametri che definiscono l'aspetto della griglia, salva i parametri che sono stati usati per ottenere i dati e salva i parametri che definiscono " dove " nell'app sono (l'azione, il controller, il percorso) - sostanzialmente un mucchio di metadati sul rapporto / griglia e su come costruirlo.

Tutti questi rapporti salvati sono disponibili in un unico elenco, che mostra il nome e la descrizione, su una determinata pagina nell'app, con ogni collegamento a un URL generico, come " / Rapporti / Salvato / 248 " (dove 248 è un esempio dell'ID del rapporto).

Ecco la parte su cui ho bisogno di aiuto:

Quando arrivo all'azione tramite l'URL "/ Rapporti / Salvato / 248" ed estrarre i metadati dal database per quel particolare report, come posso reindirizzare quei dati e la richiesta alla stessa azione, controller e route utilizzati per visualizzare la vista da cui il report è stato originariamente salvato? In sostanza, voglio che l'utente visualizzi il report nella stessa vista, con lo stesso URL da cui è stato salvato. Se possibile, mi piacerebbe poter sostanzialmente "chiamare" la stessa azione come se stessi effettuando una chiamata di metodo.


AGGIORNAMENTO: Sfortunatamente, le nostre pagine di report (ovvero le pagine su cui appaiono queste griglie) NON utilizzano URL RESTful - ad esempio, abbiamo quella che chiamiamo pagina di ricerca avanzata, che accetta un numero piuttosto elevato di potenziali parametri (quasi 30 ) che provengono da un modulo contenente elenchi, caselle di testo e così via. Quando l'utente invia quella pagina, eseguiamo un POST a un'azione che accetta un tipo complesso che il raccoglitore di modelli crea per noi - quella stessa azione è ciò che voglio chiamare quando l'utente seleziona una ricerca avanzata salvata dal database. Quell'esempio incarna il mio problema.

Grazie

È stato utile?

Soluzione

Penso che vorrai usare RedirectToAction con la firma che accetta un RouteValueDictionary. Il metodo a cui stai reindirizzando dovrà essere in grado di estrarre i valori da ValueProvider sul controller. Potrebbe assomigliare a:

public ActionResult Saved( int id )
{
    var reportParams = db.Reports.SingleOrDefault( r => r.ID == id );
    if (reportParams == null)
       ...handle error...

    var routeValues = ParamsToRouteValueDictionary( reportParams );

    return RedirectToAction( reportParams.Action, reportParams.Controller, routeValues );
}

private RouteValueDictionary ParamsToRouteValueDictionary( object parameters )
{
     var values = new RouteValueDictionary();
     var properties = parameters.GetType().GetProperties()
                                .Where( p => p.Name != "Action" && p.Name != "Controller" );
     foreach (var prop in properties)
     {
         values.Add( prop.Name, prop.GetValue(parameters,null) );
     }

     return values;
}

Modifica

L'uso di un modello di filtro come parametro per il tuo metodo potrebbe effettivamente semplificarlo. Hai solo bisogno delle versioni GET e POST della tua azione.

 [ActionName("People")]
 [AcceptVerbs( HttpVerbs.Get )]
 public ActionResult PeopleDisplay( SearchModel filter )
 {
     return People( filter );
 }

 [AcceptVerbs( HttpVerbs.Post)]
 [ValidateAntiForgeryToken]
 public ActionResult People( SearchModel filter )
 {
     ....
 }

Quindi memorizzeresti nel tuo db per il rapporto i parametri del filtro (per nome), l'Azione ("quotazione Persone") e il Controller. Il risultato di reindirizzamento utilizzerà GET e verrà indirizzato al metodo PeopleDisplay, che a sua volta chiama semplicemente il metodo People con il parametro corretto. La pubblicazione dal modulo chiama direttamente il metodo People. L'uso di due metodi consente di utilizzare il meccanismo di prevenzione CSRF. Potresti essere in grado di utilizzare un flag in TempData per assicurarti che l'azione GET sia invocata tramite il meccanismo di reindirizzamento se ti interessa limitare l'accesso ad esso.

MODIFICA FINE

Un'altra alternativa, sarebbe semplicemente archiviare anche la vista utilizzata e invece di fare un reindirizzamento, eseguire il rendering della vista appropriata. Una delle cose che dovresti considerare è che l'esecuzione del reindirizzamento finirà con un URL contenente tutti i parametri, mentre il rendering della vista lascerà l'URL da solo e mostrerà solo la stessa vista dell'URL utilizzato durante la creazione del rapporto .

Altri suggerimenti

Puoi utilizzare il metodo RedirectToAction per emettere un reindirizzamento 301 a un metodo di azione specifico su qualsiasi controller, insieme ai valori di route:

ReportMeta meta = _reportDataAccess.Get(id);
return RedirectToAction(meta.Action, meta.Controller, meta.RouteData);

dove quei valori sono qualcosa del tipo:

meta.Action = "Bar";
meta.Controller = "Foo";
meta.RouteData = new {
    // possibly settings for the grid
    start = DateTime.Min,
    end = DateTime.Now,
    sort = "Date"
    // you get the idea
};

Naturalmente, il problema immediato che posso vedere con questo è ciò che accade quando il controller / i metodi di azione cambiano nel tempo, i dati del report non saranno validi. Ma allora probabilmente ci hai già pensato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top