Übergeben von Daten an die Masterseite in ASP.NET MVC

102

Wie können Sie Daten (mit ASP.NET MVC) an die Masterseite übergeben, ohne die MVC-Regeln zu verletzen?

Ich persönlich bevorzuge es, einen abstrakten Controller (Basis-Controller) oder eine Basisklasse zu codieren, die an alle Ansichten übergeben wird.

Łukasz Sowa
quelle
1
Ich schrieb einen Leitfaden, wie ich das geschafft habe: britishdeveloper.co.uk/2010/06/… sollte helfen
BritishDeveloper

Antworten:

77

Wenn Sie möchten, dass Ihre Ansichten stark typisierte Ansichtsdatenklassen haben, funktioniert dies möglicherweise für Sie. Andere Lösungen sind wahrscheinlich korrekter, aber dies ist meiner Meinung nach eine gute Balance zwischen Design und Praktikabilität.

Die Masterseite verwendet eine stark typisierte Ansichtsdatenklasse, die nur relevante Informationen enthält:

public class MasterViewData
{
    public ICollection<string> Navigation { get; set; }
}

Jede Ansicht, die diese Masterseite verwendet, verwendet eine stark typisierte Ansichtsdatenklasse, die ihre Informationen enthält und aus den Ansichtsdaten der Masterseiten abgeleitet wird:

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
}

Da ich nicht möchte, dass einzelne Controller etwas über das Zusammenstellen der Masterseitendaten wissen, kapsle ich diese Logik in eine Factory, die an jeden Controller übergeben wird:

public interface IViewDataFactory
{
    T Create<T>()
        where T : MasterViewData, new()
}

public class ProductController : Controller
{
    public ProductController(IViewDataFactory viewDataFactory)
    ...

    public ActionResult Index()
    {
        var viewData = viewDataFactory.Create<ProductViewData>();

        viewData.Name = "My product";
        viewData.Price = 9.95;

        return View("Index", viewData);
    }
}

Die Vererbung passt gut zum Master, um die Beziehung anzuzeigen, aber wenn es um das Rendern von Partials / Benutzersteuerelementen geht, werde ich deren Ansichtsdaten in die Seitenansichtsdaten zusammensetzen, z

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
    public SubViewData SubViewData { get; set; }
}

<% Html.RenderPartial("Sub", Model.SubViewData); %>

Dies ist nur Beispielcode und soll nicht so kompiliert werden, wie er ist. Entwickelt für ASP.Net MVC 1.0.

Allgemeiner Fehler
quelle
4
Dies ist die von Scott Gutherie empfohlene Methode, daher müsste ich zustimmen.
Simon Fox
@ Simon Fox - Hast du einen Link zu Scottgus Empfehlung? Konnte es nicht finden.
Orip
Es tut uns leid. Ich habe ein wenig Probleme, einen Teil davon zu verstehen. Dem Konstruktor für den Controller wird eine Instanz von IViewDataFactory übergeben, das System erwartet jedoch einen parameterlosen Konstruktor. Ich bin auch nicht mit dieser C # -Syntax (speziell den "MasterViewData, new ()") für die Schnittstelle vertraut. Kann jemand es bitte erklären oder mich auf eine gute Ressource hinweisen. Vielen Dank.
Jason
5
Ich mag es, stark typisierte Modelle zu haben, mit denen ich arbeiten kann, aber ich bin kein großer Fan davon, die Stammdaten mit all meinen anderen Modellen und Aktionen zu koppeln. Ich bin etwas spät in diesen Thread gesprungen, aber ich habe meinen Ansatz für Stammdaten veröffentlicht, der die Dinge lockerer hält.
Todd Menier
59

Ich ziehe es vor, die datengesteuerten Teile der Master-Ansicht in Teilbilder aufzuteilen und sie mit Html.RenderAction zu rendern . Dies hat mehrere eindeutige Vorteile gegenüber dem gängigen Vererbungsansatz für Ansichtsmodelle:

  1. Stammansichtsdaten sind vollständig von "normalen" Ansichtsmodellen entkoppelt. Dies ist Komposition über Vererbung und führt zu einem locker gekoppelten System, das leichter zu ändern ist.
  2. Master-View-Modelle werden durch eine vollständig separate Controller-Aktion erstellt. "Regelmäßige" Aktionen müssen sich darüber keine Sorgen machen, und es ist keine View Data Factory erforderlich, die für meinen Geschmack übermäßig kompliziert erscheint.
  3. Wenn Sie zufällig ein Tool wie AutoMapper verwenden , um Ihre Domain Ihren Ansichtsmodellen zuzuordnen , ist die Konfiguration einfacher, da Ihre Ansichtsmodelle Ihren Domänenmodellen ähnlicher sind , wenn sie keine Stammansichtsdaten erben.
  4. Mit separaten Aktionsmethoden für Stammdaten können Sie das Ausgabe-Caching problemlos auf bestimmte Bereiche der Seite anwenden. In der Regel enthalten Masteransichten Daten, die sich weniger häufig ändern als der Inhalt der Hauptseite.
Todd Menier
quelle
3
+1. Ein weiterer Vorteil besteht darin, dass dieselbe Ansicht je nach aktuellem Laufzeitstatus unterschiedliche Masterseiten verwenden kann.
StriplingWarrior
1
Diese Antwort gefällt mir sehr gut - die anderen beschriebenen Ansätze scheinen etwas zu kompliziert.
Paddy
2
Dies ist meiner Meinung nach die eleganteste Lösung.
Autonomatt
1
Diese Lösung scheint mir auch am besten zu sein. Tausend Dank!
JimDaniel
1
Dies ist eine großartige Möglichkeit, aber denken Sie daran, dass Sie immer noch Routen für Ihre "Teilaktionen" angeben müssen. Siehe diese Antwort stackoverflow.com/a/3553617/56621
Alex
20

BEARBEITEN

Generic Error hat unten eine bessere Antwort geliefert. Bitte lies es!

Ursprüngliche Antwort

Microsoft hat tatsächlich einen Eintrag über die "offizielle" Vorgehensweise veröffentlicht . Dies bietet eine schrittweise Anleitung mit einer Erklärung ihrer Argumentation.

Kurz gesagt, sie empfehlen die Verwendung einer abstrakten Controller-Klasse, aber überzeugen Sie sich selbst.

Michael La Voie
quelle
DANKE! Dieses Beispiel ist genau das, was ich tue ... Kategorie auf jeder Seite aus der Datenbank.
Martin
Scott Gutherie, einer der Autoren von MVC, empfiehlt die von @Generic Error unten bereitgestellte Lösung
Simon Fox
1
+1 für die Anweisung zur besten Antwort, auch wenn Ihre offiziell richtig ist und von OP als Antwort akzeptiert wird.
IsmailS
+1 für die Anweisung zur besten Antwort, auch wenn Ihre offiziell richtig ist und von OP als Antwort akzeptiert wird.
Dave Jellison
Eigentlich ist Todd Menier's derzeit die beste Antwort darauf.
andreialecu
7

Abstrakte Controller sind eine gute Idee, und ich habe keinen besseren Weg gefunden. Ich bin gespannt, was andere Leute auch getan haben.

Ian P.
quelle
2

Ich finde, dass ein gemeinsames übergeordnetes Element für alle Modellobjekte, die Sie an die Ansicht übergeben, außerordentlich nützlich ist.

Es wird sowieso immer einige gemeinsame Modelleigenschaften zwischen den Seiten geben.

Matt Mitchell
quelle
0

Das Request.Params-Objekt ist veränderbar. Es ist ziemlich einfach, skalare Werte als Teil des Anforderungsverarbeitungszyklus hinzuzufügen. Aus Sicht der Ansicht könnten diese Informationen im QueryString oder FORM POST bereitgestellt worden sein. hth


quelle
0

Ich denke, dass ein anderer guter Weg darin bestehen könnte, eine Schnittstelle für die Ansicht mit einer Eigenschaft wie ParentView einer Schnittstelle zu erstellen, sodass Sie sie sowohl für Steuerelemente verwenden können, die einen Verweis auf die Seite benötigen (übergeordnetes Steuerelement), als auch für Hauptansichten, auf die zugegriffen werden soll Ansichten.

Dimarzionist
quelle
0

Die anderen Lösungen sind nicht elegant und dauern zu lange. Ich entschuldige mich dafür, dass ich fast ein Jahr später dieses sehr traurige und verarmte Ding gemacht habe:

<script runat="server" type="text/C#">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        MasterModel = SiteMasterViewData.Get(this.Context);
    }

    protected SiteMasterViewData MasterModel;
</script>

Ich habe also eindeutig diese statische Methode Get () für SiteMasterViewData, die SiteMasterViewData zurückgibt.

rasx
quelle
Für viele mag dies ein bisschen hacky oder 'unrein' erscheinen, aber es erledigt die Arbeit schnell
argh
Pfui. Ihr Code scheint viel schwieriger zu pflegen zu sein, als wenn Sie Html.RenderAction () verwendet hätten.
Dan Esparza