2013-06-07 10 views
14

Hello Razor MVC Guru:Razor MVC, dove inserire variabili globali accessibili attraverso la pagina principale, partiview e vista?

Domanda newbie.

Sfondo. Ho un'Identità personalizzata che è impostata su un HttpModule prima che arrivi al controller & visualizzazioni. Per usarlo, devo fare

MyIdentity myIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity; 
    MyComplexUser user = myIdentity.User; 
    //user.name //user.location //user.username //etc 

Il problema è, io uso l'oggetto in diversi luoghi come

  • struttura master
  • un certo livello sub layout nidificate
  • Alcune partialviews
  • Alcune viste

Davvero depe nds su quali proprietà dell'oggetto "MyComplexUser" richiedono le viste.

Attualmente, nelle viste, devo fare questo casting davvero complicato per arrivare a una proprietà. Ad esempio, se desidero il "Nome" dell'utente, devo fare

@ (((MyComplexUser) (((MyIdentity) ((GenericPrincipal) context.User) .Identity) .User)). Nome)

suppongo che ho potuto metterlo nei controllori e poi popolare il ViewBag con una proprietà ViewBag.MyUser, ma poi

  1. non mi piace usare ViewBag. Preferisco gli oggetti fortemente tipizzati
  2. Se uso un oggetto fortemente tipizzato ("MyUser") per le viste, allora devo popolare tutti quei modelli con una proprietà "MyUser". Ti senti un po 'sporco? Come mi piace mantenere i miei modelli puliti ed essere specifici per i punti di vista con cui sono coinvolti. Inoltre, diventa inutilmente ripetitivo.
  3. In luoghi come master_layout.cshtml o partialviews, come si accede a "MyUser" se li metto in un controller?
  4. Utilizzare RenderAction e creare viste parziali per ogni proprietà User è eccessivo?

Grazie. Ancora una volta, sono un principiante di MVC 4, ogni suggerimento è molto apprezzato.

+1

Ho uno scenario simile. Lo posterò come commento, se preferisci potrei aggiungere una risposta: tutti i miei controller ereditano da un 'BaseController', che ho scritto. In questa classe base, ho cablato eventi del ciclo di vita, come ad esempio 'ExecuteCore'. Uso anche filtri per cose come questa. Dal lato della vista, tutti i miei viewmodels ereditano da 'BaseVM', dove inserisco proprietà comuni, come messaggi all'utente, nome utente e così via. –

+0

@AndreCalil, potresti spiegarci un po 'di più? Quindi stai compilando un modello base dal controller di base, è così? Non riesco a ottenere la parte in cui si utilizzano i filtri, potresti fare un esempio? Inoltre, se sono state inserite le proprietà comuni nel modello di base, come si utilizza nella pagina di layout principale? do \\ @ Model BaseVM e quindi \\ @ Model.UserName? Grazie – Liming

+1

Ecco qua. E non penso che questa sia una domanda per principianti –

risposta

21

Spiegherò una soluzione simile che funziona abbastanza bene per me. Con piccole modifiche, I credo che che funzionerà per voi (e altri, si spera) pure.

Fondamentalmente, useremo l'ereditarietà .

Controller

Creiamo un controller di base personalizzato, come ad esempio

public class BaseController : Controller 

e cambiamo i nostri controllori di ereditare da esso, come

public class HomeController : BaseController 

Models (ViewModels, dico io)

Probabilmente hai un sacco di classi nei tuoi modelli fol der, giusto? Agiscono come DTO dal controller alle viste, giusto²? Se hai risposto a per entrambi, quindi continua a leggere.

Creiamo una classe del modello di base, come ad esempio public class BaseVM, e cambiamo i nostri modelli di ereditare da essa, come public class HomeIndex : BaseVM

Importante: tuo file di layout (_Layout o qualunque) deve essere fortemente tipizzato al BaseVM o un figlio di esso.

Il gancio

Ora che tutto è meravigliosamente digitato, usiamo la richiesta pipeline in nostro favore. A BaseController, si aggiungerà un metodo che assomiglia a questo:

protected override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    if (filterContext.Result is ViewResultBase)//Gets ViewResult and PartialViewResult 
    { 
     object viewModel = ((ViewResultBase)filterContext.Result).Model; 

     if (viewModel != null && viewModel is BaseVM) 
     { 
      BaseVM baseVM = viewModel as BaseVM; 

      baseVM.MyIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity; 
      //and so on... 
     } 
    } 

    base.OnActionExecuted(filterContext);//this is important! 
} 

OnActionExecuted si chiama dopo l'esecuzione dell'azione, ma prima del rendering vista. Questo è esattamente quello che vogliamo.

Spero che ce l'abbiate già. =)

+0

Grazie Andre. BaseController + BaseModel ha senso :) Grazie mille ancora! – Liming

+0

@Liming Glad to help =) –

+0

Soluzione piacevole - finalmente un modo semplice per passare oggetti a tutte le viste senza dover utilizzare ViewBag. – 79IT

Problemi correlati