2013-06-07 4 views
14

Hallo Razor MVC Gurus:Razor MVC, wo globale Variablen platziert werden können, die über Masterseite, Partiview und View zugänglich sind?

Newbie Frage.

Hintergrund. Ich habe ein benutzerdefiniertes IIdentity, das in einem HttpModule festgelegt wird, bevor es zu Controller & Aufrufe gelangt. Um es zu nutzen, ich habe

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

Das Problem ist, zu tun, verwende ich das Objekt in verschiedenen Orten wie

  • Masterlayout
  • Einige Unter Ebene verschachtelten Layouts
  • Einige partialviews
  • Einige Ansichten

Es wirklich depe nds über welche Eigenschaften von "MyComplexUser" Objekt die Ansichten benötigen.

Derzeit, in den Ansichten, muss ich das wirklich komplizierte Casting tun, um zu einer Eigenschaft zu gelangen. Zum Beispiel, wenn ich den "Namen" des Benutzers möchte, muss ich tun

@ (((MyComplexUser) (((MyIdentity) ((GenericPrincipal) Kontext.User) .Identity) .User)). Name)

nehme ich, dass ich es in den Controllern setzen könnte und dann die ViewBag mit einer ViewBag.MyUser Eigenschaft bevölkern, aber dann

  1. ich mag es nicht ViewBag verwenden. Ich bevorzuge stark typisierte Objekte
  2. Wenn ich ein stark typisiertes Objekt ("MyUser") für Ansichten verwende, dann muss ich alle diese Modelle mit einer "MyUser" -Eigenschaft populär. Fühlt sich ein bisschen schmutzig an? Ich möchte meine Models sauber halten und auf die Ansichten eingehen, mit denen sie zu tun haben. Außerdem wird es unnötigerweise wiederholt.
  3. Wie können Sie in Orten wie master_layout.cshtml oder partialviews auf "MyUser" zugreifen, wenn ich sie in einen Controller lege?
  4. Verwenden Sie RenderAction und erstellen Sie Teilansichten für jede Benutzereigenschaft ist ein Overkill?

Danke. Auch hier bin ich ein Neuling bei MVC 4, jeder Vorschlag schätzt es sehr.

+1

Ich habe ein ähnliches Szenario. Ich werde es als Kommentar veröffentlichen, wenn Sie möchten, kann ich als Antwort hinzufügen: Alle meine Controller erben von einem 'BaseController', den ich geschrieben habe. In dieser Basisklasse habe ich Ereignisse des Lebenszyklus verdrahtet, wie 'ExecuteCore'. Ich benutze auch Filter für solche Dinge. Auf der Betrachtungsseite erben alle meine Ansichtsmodelle von 'BaseVM', wo ich allgemeine Eigenschaften, wie Nachrichten an den Benutzer, Benutzernamen usw. platziere. –

+0

@AndreCalil, könnten Sie ein bisschen mehr erklären? Sie bevölkern also ein Basismodell vom Basis-Controller, oder? Ich bekomme nicht den Teil, wo Sie Filter verwenden, können Sie ein Beispiel geben? Wenn Sie die allgemeinen Eigenschaften im Basismodell ausgefüllt haben, wie verwenden Sie sie dann in der Hauptlayoutseite? Do \\ @ Model BaseVM und dann \\ @ Model.UserName? Danke – Liming

+1

Da gehen Sie. Und ich glaube nicht, dass das überhaupt eine Anfängerfrage ist. –

Antwort

21

Ich werde eine ähnliche Lösung erklären, die ziemlich gut für mich funktioniert. Mit kleinen Änderungen glaube ich , dass es für Sie (und andere, hoffentlich) ebenso gut funktioniert.

Grundsätzlich verwenden wir Vererbung.

Controller

Lassen Sie uns eine eigene Basis-Controller erstellen, wie

public class BaseController : Controller 

und wir unsere Controller von ihm zu erben ändern, da

public class HomeController : BaseController 

Models (Viewmodels, sage ich)

Sie haben wahrscheinlich viele Klassen in Ihrem Modell fol der, oder? Sie agieren als DTOs vom Controller zu den Ansichten, richtig? Wenn Sie ja für beide beantwortet haben, dann lesen Sie weiter.

Lassen Sie sich eine Basismodell-Klasse erstellen, wie public class BaseVM, und lassen Sie sich unsere Modelle von ihm zu erben ändern, wie public class HomeIndex : BaseVM

Wichtig: Ihrer Layout-Datei (_Layout oder was auch immer) muss BaseVM stark typisiert werden oder ein Kind davon.

Der Haken

Jetzt beautifuly getippt, dass alles, lassen Sie uns die Anfrage Pipeline zu unseren Gunsten nutzen. Bei BaseController finden Sie eine Methode hinzufügen, die wie folgt aussieht:

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 heißt nach die Ausführung der Aktion aber vor die Ansicht Rendering. Genau das wollen wir.

Ich hoffe, du hast es schon. =)

+0

Got it! Danke Andre. BaseController + BaseModel macht Sinn :) Nochmals vielen Dank! – Liming

+0

@Liming Gut zu helfen =) –

+0

Schöne Lösung - endlich eine einfache Möglichkeit, Objekte an alle Ansichten zu übergeben, ohne ViewBag verwenden zu müssen. – 79IT

Verwandte Themen