Przekazywanie danych do stron wzorcowych widoku (C#)

autor: Microsoft

Pobierz plik PDF

Celem tego samouczka jest wyjaśnienie sposobu przekazywania danych z kontrolera do strony wzorcowej widoku. Analizujemy dwie strategie przekazywania danych do strony wzorcowej widoku. Najpierw omówimy łatwe rozwiązanie, które powoduje, że aplikacja jest trudna do utrzymania. Następnie przeanalizujemy znacznie lepsze rozwiązanie, które wymaga nieco większej pracy początkowej, ale powoduje znacznie bardziej konserwację aplikacji.

Przekazywanie danych do widoku stron wzorcowych

Celem tego samouczka jest wyjaśnienie sposobu przekazywania danych z kontrolera do strony wzorcowej widoku. Analizujemy dwie strategie przekazywania danych do strony wzorcowej widoku. Najpierw omówimy łatwe rozwiązanie, które powoduje, że aplikacja jest trudna do utrzymania. Następnie przeanalizujemy znacznie lepsze rozwiązanie, które wymaga nieco większej pracy początkowej, ale powoduje znacznie bardziej konserwację aplikacji.

The Problem

Załóżmy, że tworzysz aplikację bazy danych filmów i chcesz wyświetlić listę kategorii filmów na każdej stronie w aplikacji (zobacz Rysunek 1). Wyobraź sobie ponadto, że lista kategorii filmów jest przechowywana w tabeli bazy danych. W takim przypadku warto pobrać kategorie z bazy danych i renderować listę kategorii filmów na stronie wzorcowej widoku.

Wyświetlanie kategorii filmów na stronie wzorcowej widoku

Rysunek 01. Wyświetlanie kategorii filmów na stronie wzorcowej widoku (kliknij, aby wyświetlić obraz pełnowymiarowy)

Oto problem. Jak pobrać listę kategorii filmów na stronie wzorcowej? Kuszące jest bezpośrednie wywołanie metod klas modelu na stronie wzorcowej. Innymi słowy, kuszące jest dołączenie kodu do pobierania danych z bazy danych bezpośrednio na stronie wzorcowej. Jednak pominięcie kontrolerów MVC w celu uzyskania dostępu do bazy danych naruszałoby czystą separację obaw, które są jednym z podstawowych korzyści związanych z tworzeniem aplikacji MVC.

W aplikacji MVC chcesz, aby wszystkie interakcje między widokami MVC i modelem MVC być obsługiwane przez kontrolery MVC. To rozdzielenie obaw skutkuje bardziej konserwowalnym, dostosowywanym i testowalnym zastosowaniem.

W aplikacji MVC wszystkie dane przekazane do widoku — w tym strona wzorcowa widoku — powinny być przekazywane do widoku przez akcję kontrolera. Ponadto dane powinny być przekazywane, korzystając z danych widoku. W pozostałej części tego samouczka badam dwie metody przekazywania danych widoku do strony wzorcowej widoku widoku.

Proste rozwiązanie

Zacznijmy od najprostszego rozwiązania do przekazywania danych widoku z kontrolera do strony wzorcowej widoku. Najprostszym rozwiązaniem jest przekazanie danych widoku dla strony wzorcowej w każdej akcji kontrolera.

Rozważ kontroler w liście 1. Uwidacznia dwie akcje o nazwie Index() i Details(). Metoda Index() akcji zwraca każdy film w tabeli bazy danych Filmy. Metoda Details() akcji zwraca każdy film w określonej kategorii filmów.

Lista 1 — Controllers\HomeController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
     [HandleError]
     public class HomeController : Controller
     {
          private MovieDataContext _dataContext = new MovieDataContext();

          /// <summary>

          /// Show list of all movies
          /// </summary>
          public ActionResult Index()
          {
               ViewData["categories"] = from c in _dataContext.MovieCategories 
                         select c;
               ViewData["movies"] = from m in _dataContext.Movies 
                         select m;
               return View();
          }

          /// <summary>
          /// Show list of movies in a category
          /// </summary>

          public ActionResult Details(int id)
          {
               ViewData["categories"] = from c in _dataContext.MovieCategories 
                         select c;
               ViewData["movies"] = from m in _dataContext.Movies 
                         where m.CategoryId == id
                         select m;
               return View();
          }
     }
}

Zwróć uwagę, że zarówno akcje Index() i Details() dodają dwa elementy, aby wyświetlić dane. Akcja Index() dodaje dwa klucze: kategorie i filmy. Klucz kategorii reprezentuje listę kategorii filmów wyświetlanych na stronie wzorcowej widoku. Klucz filmów reprezentuje listę filmów wyświetlanych na stronie Widok indeksu.

Akcja Details() dodaje również dwa klucze o nazwach kategorii i filmów. Klucz kategorii, po raz kolejny, reprezentuje listę kategorii filmów wyświetlanych na stronie wzorcowej widoku. Klucz filmów reprezentuje listę filmów w określonej kategorii wyświetlanej na stronie Widok szczegółów (patrz Rysunek 2).

Widok Szczegółów

Rysunek 02. Widok szczegółów (kliknij, aby wyświetlić obraz pełnowymiarowy)

Widok indeksu znajduje się na liście 2. Po prostu iteruje listę filmów reprezentowanych przez element filmów w danych widoku.

Lista 2 — Views\Home\Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>

<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

<ul>

<% foreach (var m in (IEnumerable<Movie>)ViewData["movies"])
     { %>

     <li><%= m.Title %></li>

<% } %>
</ul>

</asp:Content>

Strona wzorcowa widoku znajduje się na liście 3. Strona wzorcowa widoku iteruje i renderuje wszystkie kategorie filmów reprezentowane przez element kategorii z danych widoku.

Lista 3 — Views\Shared\Site.master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="MvcApplication1.Views.Shared.Site" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
     <title></title>
     <asp:ContentPlaceHolder ID="head" runat="server">

     </asp:ContentPlaceHolder>
</head>
<body>
     <div>
          <h1>My Movie Website</h1>

          <% foreach (var c in (IEnumerable<MovieCategory>)ViewData["categories"])
                           {%>

               <%= Html.ActionLink(c.Name, "Details", new {id=c.Id} ) %> 

          <% } %>


          <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

          </asp:ContentPlaceHolder>
     </div>
</body>
</html>

Wszystkie dane są przekazywane do widoku i strony wzorcowej widoku za pośrednictwem danych widoku. Jest to prawidłowy sposób przekazywania danych do strony wzorcowej.

Więc co jest nie tak z tym rozwiązaniem? Problem polega na tym, że to rozwiązanie narusza zasadę DRY (Nie powtarzaj siebie). Każda akcja kontrolera musi dodać tę samą listę kategorii filmów, aby wyświetlić dane. Duplikowanie kodu w aplikacji znacznie utrudnia konserwację, dostosowywanie i modyfikowanie aplikacji.

Dobre rozwiązanie

W tej sekcji przyjrzymy się alternatywnemu i lepszemu rozwiązaniu do przekazywania danych z akcji kontrolera do strony wzorcowej widoku. Zamiast dodawać kategorie filmów dla strony wzorcowej w każdej akcji kontrolera, dodamy kategorie filmów do wyświetlania danych tylko raz. Wszystkie dane widoku używane przez stronę wzorcową widoku są dodawane do kontrolera aplikacji.

Klasa ApplicationController znajduje się na liście 4.

Lista 4 — Controllers\ApplicationController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
     public abstract class ApplicationController : Controller
     {
          private MovieDataContext _dataContext = new MovieDataContext();

          public MovieDataContext DataContext
          {
               get { return _dataContext; }
          }

          public ApplicationController()
          {
               ViewData["categories"] = from c in DataContext.MovieCategories 
                         select c;
          }

     }
}

Istnieją trzy elementy, które należy zauważyć na temat kontrolera aplikacji na liście 4. Najpierw zwróć uwagę, że klasa dziedziczy z podstawowej klasy System.Web.Mvc.Controller. Kontroler aplikacji jest klasą kontrolera.

Po drugie, zwróć uwagę, że klasa kontrolera aplikacji jest klasą abstrakcyjną. Klasa abstrakcyjna to klasa, która musi zostać zaimplementowana przez konkretną klasę. Ponieważ kontroler aplikacji jest klasą abstrakcyjną, nie można bezpośrednio wywołać żadnych metod zdefiniowanych w klasie. Jeśli spróbujesz wywołać klasę Application bezpośrednio, zostanie wyświetlony komunikat o błędzie Nie można odnaleźć zasobu.

Po trzecie, należy zauważyć, że kontroler aplikacji zawiera konstruktor, który dodaje listę kategorii filmów do wyświetlania danych. Każda klasa kontrolera dziedziczona z kontrolera aplikacji automatycznie wywołuje konstruktor kontrolera aplikacji. Za każdym razem, gdy wywołujesz dowolną akcję na dowolnym kontrolerze, który dziedziczy z kontrolera aplikacji, kategorie filmów są automatycznie uwzględniane w danych widoku.

Kontroler filmów na liście 5 dziedziczy z kontrolera aplikacji.

Lista 5 — Controllers\MoviesController.cs

using System.Linq;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
     public class MoviesController : ApplicationController
     {
          /// <summary>

          /// Show list of all movies
          /// </summary>
          public ActionResult Index()
          {
               ViewData["movies"] = from m in DataContext.Movies 
                         select m;
               return View();
          }

          /// <summary>
          /// Show list of movies in a category
          /// </summary>

          public ActionResult Details(int id)
          {
               ViewData["movies"] = from m in DataContext.Movies
                         where m.CategoryId == id
                         select m;
               return View();
          }

     }
}

Kontroler Filmów, podobnie jak kontroler główny omówiony w poprzedniej sekcji, udostępnia dwie metody akcji o nazwie Index() i Details(). Zwróć uwagę, że lista kategorii filmów wyświetlanych przez stronę wzorcową widoku nie jest dodawana do wyświetlania danych w metodzie Index() lub Details() . Ponieważ kontroler Filmy dziedziczy z kontrolera aplikacji, lista kategorii filmów jest dodawana do automatycznego wyświetlania danych.

Zwróć uwagę, że to rozwiązanie do dodawania danych widoku dla strony wzorcowej widoku nie narusza zasady DRY (Nie powtarzaj siebie). Kod dodawania listy kategorii filmów do wyświetlania danych znajduje się tylko w jednej lokalizacji: konstruktor kontrolera aplikacji.

Podsumowanie

W tym samouczku omówiliśmy dwie metody przekazywania danych widoku z kontrolera do strony wzorcowej widoku. Najpierw zbadaliśmy proste, ale trudne do utrzymania podejście. W pierwszej sekcji omówiono sposób dodawania danych widoku dla strony wzorcowej widoku w każdej akcji kontrolera w aplikacji. Doszliśmy do wniosku, że jest to złe podejście, ponieważ narusza zasadę DRY (Nie powtarzaj siebie).

Następnie przeanalizowaliśmy znacznie lepszą strategię dodawania danych wymaganych przez stronę wzorcową widoku w celu wyświetlenia danych. Zamiast dodawać dane widoku w każdej akcji kontrolera, dodaliśmy dane widoku tylko raz w ramach kontrolera aplikacji. Dzięki temu można uniknąć duplikowania kodu podczas przekazywania danych do strony wzorcowej widoku w aplikacji ASP.NET MVC.