Поделиться через


Передача данных на эталонные страницы представлений (C#)

от Майкрософт

Загрузить PDF-файл

Цель этого руководства — объяснить, как можно передать данные из контроллера в представление master страницу. Мы рассмотрим две стратегии передачи данных в представление master страницу. Во-первых, мы обсудим простое решение, которое приводит к сложному в обслуживании приложению. Далее мы рассмотрим гораздо лучшее решение, которое требует немного больше первоначальной работы, но приводит к гораздо более удобному для обслуживания приложению.

Передача данных в представление главных страниц

Цель этого руководства — объяснить, как можно передать данные из контроллера в представление master страницу. Мы рассмотрим две стратегии передачи данных в представление master страницу. Во-первых, мы обсудим простое решение, которое приводит к сложному в обслуживании приложению. Далее мы рассмотрим гораздо лучшее решение, которое требует немного больше первоначальной работы, но приводит к гораздо более удобному для обслуживания приложению.

Проблема

Представьте, что вы создаете приложение базы данных фильмов и хотите отобразить список категорий фильмов на каждой странице приложения (см. рис. 1). Кроме того, представьте, что список категорий фильмов хранится в таблице базы данных. В этом случае имеет смысл извлечь категории из базы данных и отобразить список категорий фильмов в представлении master странице.

Отображение категорий фильмов на странице представления master

Рис. 01. Отображение категорий фильмов в представлении master странице (щелкните для просмотра полноразмерного изображения)

Вот в чем проблема. Как получить список категорий фильмов на странице master? Заманчиво вызывать методы классов модели на странице master напрямую. Иными словами, заманчиво включить код для извлечения данных из базы данных прямо на страницу master. Однако обход контроллеров MVC для доступа к базе данных приведет к нарушению четкого разделения задач, что является одним из основных преимуществ создания приложения MVC.

В приложении MVC необходимо, чтобы все взаимодействие между представлениями MVC и моделью MVC обрабатывалось контроллерами MVC. Такое разделение задач приводит к тому, что приложение будет более поддерживаемым, адаптируемым и тестируемым.

В приложении MVC все данные, передаваемые в представление, включая представление master страницу, должны передаваться в представление действием контроллера. Кроме того, данные следует передавать, используя преимущества данных просмотра. В оставшейся части этого руководства мы рассмотрим два метода передачи данных представления в представление master страницу.

Простое решение

Начнем с самого простого решения для передачи данных представления с контроллера на страницу представления master. Простейшим решением является передача данных представления для страницы master в каждом действии контроллера.

Рассмотрим контроллер в листинге 1. Он предоставляет два действия с именами Index() и Details(). Метод Index() действия возвращает каждый фильм в таблице базы данных Movies. Метод Details() действия возвращает каждый фильм в определенной категории фильмов.

Листинг 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();
          }
     }
}

Обратите внимание, что действия Index() и Details() добавляют два элемента для просмотра данных. Действие Index() добавляет два ключа: категории и фильмы. Ключ категорий представляет список категорий фильмов, отображаемых на странице представления master. Ключ movies представляет список фильмов, отображаемых на странице представления индекса.

Действие Details() также добавляет два ключа с именами категорий и фильмов. Ключ категорий еще раз представляет список категорий фильмов, отображаемых на странице представления master. Клавиша movies представляет список фильмов в определенной категории, отображаемый на странице представления сведений (см. рис. 2).

Представление

Рис. 02. Представление сведений (щелкните, чтобы просмотреть полноразмерное изображение)

Представление индекса содержится в листинге 2. Он просто выполняет итерацию по списку фильмов, представленных элементом movies в данных представления.

Листинг 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>

Страница master представления содержится в листинге 3. Страница представления master выполняет итерацию и отрисовывает все категории фильмов, представленные элементом категорий из данных представления.

Листинг 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>

Все данные передаются в представление, а представление master страницу через данные представления. Это правильный способ передачи данных на страницу master.

Итак, что не так с этим решением? Проблема заключается в том, что это решение нарушает принцип DRY (не повторяйся). Каждое действие контроллера должно добавлять один и тот же список категорий фильмов для просмотра данных. Наличие дубликата кода в приложении значительно усложняет обслуживание, адаптацию и изменение приложения.

Хорошее решение

В этом разделе мы рассмотрим альтернативное и лучшее решение для передачи данных из действия контроллера в представление master страницу. Вместо добавления категорий фильмов для страницы master в каждом действии контроллера мы добавляем категории фильмов в данные представления только один раз. Все данные представления, используемые страницей master представления, добавляются в контроллер приложения.

Класс ApplicationController содержится в листинге 4.

Листинг 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;
          }

     }
}

В листинге 4 следует обратить внимание на три вещи, касающиеся контроллера приложения. Во-первых, обратите внимание, что класс наследуется от базового класса System.Web.Mvc.Controller. Контроллер приложения — это класс контроллера.

Во-вторых, обратите внимание, что класс контроллера приложения является абстрактным классом. Абстрактный класс — это класс, который должен быть реализован конкретным классом. Так как контроллер приложения является абстрактным классом, нельзя напрямую вызывать методы, определенные в классе . При попытке вызвать класс Application напрямую появится сообщение об ошибке Resource Cannot Be Found (Ресурс не найден).

В-третьих, обратите внимание, что контроллер приложения содержит конструктор, который добавляет список категорий фильмов для просмотра данных. Каждый класс контроллера, наследующий от контроллера приложения, автоматически вызывает конструктор контроллера приложения. Всякий раз, когда вы вызываете какое-либо действие для любого контроллера, наследуемого от контроллера приложения, категории фильмов включаются в данные представления автоматически.

Контроллер Movies в листинге 5 наследуется от контроллера приложения.

Листинг 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();
          }

     }
}

Контроллер Movies, как и контроллер Home, описанный в предыдущем разделе, предоставляет два метода действий с именами Index() и Details(). Обратите внимание, что список категорий фильмов, отображаемых на странице представления master, не добавляется для просмотра данных ни в методе , ни в методе Index() или Details() . Так как контроллер Movies наследует от контроллера приложения, список категорий фильмов добавляется для автоматического просмотра данных.

Обратите внимание, что это решение для добавления данных представления master страницы не нарушает принцип DRY (не повторяйся). Код для добавления списка категорий фильмов для просмотра данных содержится только в одном расположении: конструкторе для контроллера приложения.

Итоги

В этом руководстве мы рассмотрели два подхода к передаче данных представления из контроллера в представление master страницу. Во-первых, мы рассмотрели простой, но трудный в обслуживании подход. В первом разделе мы рассмотрели, как добавить данные представления для master страницы в каждом действии контроллера в приложении. Мы пришли к выводу, что это был плохой подход, поскольку он нарушает принцип DRY (не повторяйся).

Далее мы рассмотрели гораздо более эффективную стратегию добавления данных, необходимых для просмотра master страницы представления. Вместо добавления данных представления в каждое действие контроллера мы добавили данные представления только один раз в контроллере приложения. Таким образом можно избежать дублирования кода при передаче данных в представление master страницу в приложении ASP.NET MVC.