Przekazywanie danych do strony wzorcowej w ASP.NET MVC

102

Jaki jest Twój sposób przekazywania danych do strony wzorcowej (przy użyciu ASP.NET MVC) bez łamania reguł MVC?

Osobiście wolę kodować abstrakcyjny kontroler (kontroler bazowy) lub klasę bazową, która jest przekazywana do wszystkich widoków.

Łukasz Sowa
źródło
1
Napisałem poradnik, jak sobie z tym poradziłem : britishdeveloper.co.uk/2010/06/… powinien pomóc
BritishDeveloper

Odpowiedzi:

77

Jeśli wolisz, aby Twoje widoki miały silnie wpisane klasy danych widoku, może to zadziałać. Inne rozwiązania są prawdopodobnie bardziej poprawne, ale jest to niezła równowaga między designem a praktycznością IMHO.

Strona wzorcowa przyjmuje silnie wpisaną klasę danych widoku zawierającą tylko istotne dla niej informacje:

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

Każdy widok korzystający z tej strony wzorcowej przyjmuje silnie wpisaną klasę danych widoku zawierającą informacje i pochodzącą z danych widoku stron wzorcowych:

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

Ponieważ nie chcę, aby poszczególni kontrolerzy wiedzieli cokolwiek o łączeniu danych ze stron wzorcowych, umieszczam tę logikę w fabryce, która jest przekazywana do każdego kontrolera:

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

Dziedziczenie dopasowuje wzorzec, aby dobrze wyświetlać relację, ale jeśli chodzi o renderowanie części / elementów sterujących użytkownika, skomponuję ich dane widoku do danych widoku stron, np.

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

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

To jest tylko przykładowy kod i nie jest przeznaczony do kompilacji w obecnej postaci. Zaprojektowany dla ASP.Net MVC 1.0.

Błąd ogólny
źródło
4
To metoda polecana przez Scotta Gutheriego, więc musiałbym się zgodzić.
Simon Fox
@Simon Fox - masz link do rekomendacji Scottgu? Nie mogłem go znaleźć.
lubip
Przepraszam. Mam trochę problemów ze zrozumieniem części tego. Konstruktor kontrolera otrzymuje wystąpienie IViewDataFactory, ale system oczekuje konstruktora bez parametrów. Nie znam również tej składni języka C # (w szczególności „MasterViewData, new ()”) interfejsu. Czy ktoś może mi to wyjaśnić lub wskazać dobre źródło informacji. Dzięki.
Jason
5
Lubię mieć mocno wpisane modele do pracy, ale nie jestem wielkim fanem łączenia danych podstawowych ze wszystkimi innymi moimi modelami i działaniami. Wskoczyłem do tego wątku trochę późno, ale opublikowałem swoje podejście do danych podstawowych, które sprawia, że ​​sprawy są bardziej luźne.
Todd Menier
59

Wolę rozbijać elementy widoku głównego oparte na danych na części i renderować je za pomocą Html.RenderAction . Ma to kilka wyraźnych zalet w porównaniu z popularnym podejściem do dziedziczenia modelu widoku:

  1. Dane widoku głównego są całkowicie oddzielone od „zwykłych” modeli widoku. Jest to kompozycja nad dziedziczeniem i skutkuje bardziej luźno powiązanym systemem, który jest łatwiejszy do zmiany.
  2. Modele widoku głównego są tworzone przez całkowicie oddzielną akcję kontrolera. „Regularne” działania nie muszą się tym martwić i nie ma potrzeby korzystania z fabryki danych widoku, co wydaje się zbyt skomplikowane, jak na mój gust.
  3. Jeśli zdarzy ci się użyć narzędzia takiego jak AutoMapper do mapowania domeny na modele widoku, konfiguracja będzie łatwiejsza, ponieważ modele widoku będą bardziej przypominać modele domeny, gdy nie dziedziczą danych widoku głównego.
  4. Dzięki oddzielnym metodom akcji dla danych głównych można łatwo zastosować buforowanie danych wyjściowych do określonych regionów strony. Zazwyczaj widoki główne zawierają dane, które zmieniają się rzadziej niż zawartość strony głównej.
Todd Menier
źródło
3
+1. Kolejną zaletą jest to, że ten sam widok może korzystać z różnych stron wzorcowych w zależności od bieżącego stanu środowiska wykonawczego.
StriplingWarrior
1
Bardzo podoba mi się ta odpowiedź - inne przedstawione podejścia wydają się nieco zbyt skomplikowane.
Paddy
2
To moim zdaniem najbardziej eleganckie rozwiązanie.
autonomatt
1
To rozwiązanie wydaje mi się najlepsze. Stukrotne dzięki!
JimDaniel
1
To świetny sposób, ale pamiętaj, że nadal musisz określić trasy do swoich „akcji częściowych”. Zobacz tę odpowiedź stackoverflow.com/a/3553617/56621
Alex
20

EDYTOWAĆ

Poniżej znajdziesz lepszą odpowiedź na to pytanie ogólne . Proszę przeczytaj to!

Oryginalna odpowiedź

Microsoft faktycznie opublikował wpis dotyczący „oficjalnego” sposobu radzenia sobie z tym problemem. Jest to przewodnik krok po kroku z wyjaśnieniem ich uzasadnienia.

Krótko mówiąc, zalecają użycie abstrakcyjnej klasy kontrolera, ale przekonaj się sam.

Michael La Voie
źródło
DZIĘKUJĘ CI! Ten przykład jest DOKŁADNIE tym, co robię ... kategoria na każdej stronie pochodzącej z bazy danych.
Martin
Scott Gutherie, jeden z autorów MVC poleca rozwiązanie dostarczone przez @Generic Error poniżej
Simon Fox
1
+1 za skierowanie do najlepszej odpowiedzi, nawet jeśli twoja jest oficjalnie słuszna i zaakceptowana jako odpowiedź przez OP.
IsmailS
+1 za skierowanie do najlepszej odpowiedzi, nawet jeśli twoja jest oficjalnie słuszna i zaakceptowana jako odpowiedź przez OP.
Dave Jellison
Właściwie Todd Menier's jest obecnie najlepszą odpowiedzią na to.
andreialecu
7

Abstrakcyjne kontrolery to dobry pomysł i nie znalazłem lepszego sposobu. Interesuje mnie też, co zrobili inni ludzie.

Ian P
źródło
2

Uważam, że wspólny rodzic dla wszystkich obiektów modelu, które przekazujesz do widoku, jest wyjątkowo przydatny.

I tak zawsze będą istnieć pewne typowe właściwości modelu między stronami.

Matt Mitchell
źródło
0

Obiekt Request.Params jest zmienny. Dość łatwo jest dodać do niego wartości skalarne w ramach cyklu przetwarzania żądania. Z perspektywy widoku te informacje mogły zostać podane w QueryString lub FORM POST. hth


źródło
0

Myślę, że innym dobrym sposobem mogłoby być utworzenie interfejsu do widoku z pewną właściwością, taką jak ParentView jakiegoś interfejsu, dzięki czemu można go używać zarówno do kontrolek, które wymagają odniesienia do strony (kontrola nadrzędna), jak i do widoków głównych, do których należy uzyskać dostęp z wyświetlenia.

dimarzionista
źródło
0

Innym rozwiązaniom brakuje elegancji i trwają zbyt długo. Przepraszam za zrobienie tej bardzo smutnej i zubożałej rzeczy prawie cały rok później:

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

    protected SiteMasterViewData MasterModel;
</script>

Więc wyraźnie mam tę statyczną metodę Get () w SiteMasterViewData, która zwraca SiteMasterViewData.

rasx
źródło
Dla wielu może to wydawać się nieco hacky lub „nieczyste”, ale dostaje zadanie preety szybko
argh
Fuj. Twój kod wydaje się dużo trudniejszy do utrzymania, gdybyś użył Html.RenderAction ().
Dan Esparza,