Passer des données à la page maître dans ASP.NET MVC

102

Quelle est votre façon de transmettre des données à la page maître (à l'aide d'ASP.NET MVC) sans enfreindre les règles MVC?

Personnellement, je préfère coder un contrôleur abstrait (contrôleur de base) ou une classe de base qui est passée à toutes les vues.

Łukasz Sowa
la source
1
J'ai écrit un guide sur la façon dont j'ai géré cela: britishdeveloper.co.uk/2010/06/… devrait aider
BritishDeveloper

Réponses:

77

Si vous préférez que vos vues aient des classes de données de vue fortement typées, cela peut fonctionner pour vous. D'autres solutions sont probablement plus correctes mais c'est un bel équilibre entre le design et l'aspect pratique à mon humble avis.

La page maître prend une classe de données de vue fortement typée contenant uniquement des informations pertinentes:

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

Chaque vue utilisant cette page maître utilise une classe de données de vue fortement typée contenant ses informations et dérivant des données de vue des pages maîtres:

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

Puisque je ne veux pas que les contrôleurs individuels sachent quoi que ce soit sur la compilation des données des pages maîtres, j'encapsule cette logique dans une usine qui est transmise à chaque contrôleur:

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

L'héritage correspond au maître pour bien visualiser la relation, mais quand il s'agit de rendre les partiels / contrôles utilisateur, je vais composer leurs données de vue dans les données de vue des pages, par exemple

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

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

Ceci est un exemple de code uniquement et n'est pas destiné à être compilé tel quel. Conçu pour ASP.Net MVC 1.0.

Erreur générique
la source
4
C'est la méthode recommandée par Scott Gutherie, je devrais donc être d'accord.
Simon Fox
@Simon Fox - Vous avez un lien vers la recommandation de Scottgu? Je n'ai pas pu le trouver.
orip
Désolé. Avoir un peu de mal à comprendre une partie de cela. Le constructeur du contrôleur reçoit une instance de IViewDataFactory mais le système attend un constructeur sans paramètre. Je ne suis pas non plus familier avec cette syntaxe C # (en particulier le "MasterViewData, new ()") pour l'interface. Quelqu'un peut-il s'il vous plaît l'expliquer ou me diriger vers une bonne ressource. Merci.
Jason
5
J'aime travailler avec des modèles fortement typés, mais je ne suis pas un grand fan du couplage des données de base avec tous mes autres modèles et actions. Sauter dans ce fil un peu tard, mais j'ai publié mon approche des données de base qui garde les choses plus lâches.
Todd Menier
59

Je préfère séparer les éléments de la vue principale basés sur les données en partiels et les rendre à l'aide de Html.RenderAction . Cela présente plusieurs avantages distincts par rapport à l'approche populaire d'héritage du modèle de vue:

  1. Les données de vue principale sont complètement découplées des modèles de vue "normaux". Il s'agit de la composition plutôt que de l'héritage et il en résulte un système plus faiblement couplé qui est plus facile à modifier.
  2. Les modèles de vue principale sont créés par une action de contrôleur complètement séparée. Les actions "régulières" n'ont pas besoin de s'inquiéter à ce sujet, et il n'y a pas besoin d'une fabrique de données de vue, ce qui semble trop compliqué à mon goût.
  3. Si vous utilisez un outil tel qu'AutoMapper pour mapper votre domaine à vos modèles de vue, vous le trouverez plus facile à configurer, car vos modèles de vue ressembleront davantage à vos modèles de domaine lorsqu'ils n'hériteront pas des données de vue principale.
  4. Avec des méthodes d'action distinctes pour les données de base, vous pouvez facilement appliquer la mise en cache de sortie à certaines régions de la page. Les vues principales contiennent généralement des données qui changent moins fréquemment que le contenu de la page principale.
Todd Menier
la source
3
+1. Un autre avantage est que vous pouvez faire en sorte que la même vue utilise différentes pages maîtres en fonction de l'état d'exécution actuel.
StriplingWarrior
1
J'aime beaucoup cette réponse - les autres approches décrites semblent un peu trop compliquées.
Paddy
2
C'est la solution la plus élégante à mon avis.
autonomatt
1
Cette solution me semble également la meilleure. Mille mercis!
JimDaniel
1
C'est un excellent moyen, mais rappelez-vous que vous devez toujours spécifier des routes vers vos "actions partielles". Voir cette réponse stackoverflow.com/a/3553617/56621
Alex
20

ÉDITER

Generic Error a fourni une meilleure réponse ci-dessous. Lisez-le s'il vous plaît!

Réponse originale

Microsoft a en fait publié une entrée sur la manière «officielle» de gérer cela. Cela fournit une étape par étape avec une explication de leur raisonnement.

En bref, ils recommandent d'utiliser une classe de contrôleur abstraite, mais voyez par vous-même.

Michael La Voie
la source
MERCI! Cet exemple est exactement ce que je fais ... catégorie sur chaque page provenant de la base de données.
Martin
Scott Gutherie, l'un des auteurs de MVC recommande la solution fournie par @Generic Error ci
Simon Fox
1
+1 pour diriger vers la meilleure réponse même lorsque la vôtre a officiellement raison et acceptée comme réponse par OP.
IsmailS
+1 pour diriger vers la meilleure réponse même lorsque la vôtre a officiellement raison et acceptée comme réponse par OP.
Dave Jellison
En fait, Todd Menier est actuellement la meilleure réponse pour cela.
andreialecu
7

Les contrôleurs abstraits sont une bonne idée, et je n'ai pas trouvé de meilleur moyen. Je suis également intéressé de voir ce que d'autres personnes ont fait.

Ian P
la source
2

Je trouve qu'un parent commun pour tous les objets de modèle que vous passez à la vue est exceptionnellement utile.

De toute façon, il y aura toujours des propriétés de modèle communes entre les pages.

Matt Mitchell
la source
0

L'objet Request.Params est modifiable. Il est assez facile d'y ajouter des valeurs scalaires dans le cadre du cycle de traitement des demandes. Du point de vue de la vue, ces informations auraient pu être fournies dans QueryString ou FORM POST. hth


la source
0

Je pense qu'un autre bon moyen pourrait être de créer une interface pour la vue avec une propriété comme ParentView d'une interface, afin que vous puissiez l'utiliser à la fois pour les contrôles qui nécessitent une référence à la page (contrôle parent) et pour les vues principales qui doivent être accessibles à partir de vues.

dimarzioniste
la source
0

Les autres solutions manquent d'élégance et prennent trop de temps. Je m'excuse d'avoir fait cette chose très triste et appauvrie presque un an plus tard:

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

    protected SiteMasterViewData MasterModel;
</script>

Il est donc clair que j'ai cette méthode statique Get () sur SiteMasterViewData qui renvoie SiteMasterViewData.

rasx
la source
pour beaucoup, cela peut sembler un peu piraté ou `` impur '', mais cela fait le travail rapidement
argh
Pouah. Votre code semble beaucoup plus difficile à maintenir que si vous aviez utilisé Html.RenderAction ().
Dan Esparza