Хелпикс

Главная

Контакты

Случайная статья





Лекция__ __ Методология model-view-control.



Лекция__ __ Методология model-view-control.

 

План лекции:

1. Общие сведения об Asp.NET MVC

2. Структура проекта ASP.NET MVC  

 

1. Общие сведения об Asp.NET MVC

В.NET Framework 3.5 появилась новая технология – ASP.NET MVC. Ее отличие от обычного ASP.NET заключается в том, что за основу взят не шаблон проектирования PageController, когда создается множество страниц (часто для любого действия создается своя страница), а FrontController, когда создается небольшое количество классов, способных обрабатывать запросы и генерировать разметку страницы (или при использовании AJAX части страницы) исходя из переданных данных.

Примечание: Оба подхода имеют одинаковую выразительную мощность и преимущественно отличаются подходом к разработке. Так в классическом ASP.NET также можно реализовать подход, основанный на controller' ах, когда весь код страницы будет динамически генерироваться в методе Page_Load(). При этом те преимущества, которые предоставляет MVC можно реализовать и в ASP.NET. Некоторые примеры этого будут показаны в следующих лекциях.

ASP.NET MVC является реализаций шаблона Model-View-Controller под платформу .NET. Рассмотрим основные принципы его работы.

Архитектурный шаблон Model-View-Controller подразумевает под собой разделение приложения на три основных компонента: Model, View и Controller. Каждый из этих компонентов отвечает за свои задачи:

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

· View отвечает за взаимодействие с пользователем (UI). Посредством этого компонента будут выводиться данные клиенту, реализовываться интерфейс для их редактирования и т.п.

· Controller – это связующее звено между первыми двумя компонентами. Controller получает данные о запросе к серверу, обрабатывает эти данные (например, получает значения из отправленной формы) и передает их в Model. После обработки или получения данных он выбирает, каким же именно способом отобразить данные клиенту (нужный View ).

В результате получается полный контроль над выводимым HTML и более "легкие" приложения. Также значительно упрощается тестирование приложений, так как теперь можно легко писать Unit Test'ы для модели и контроллера.

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

Также стоит отметить, что в таком подходе отсутствует ViewState, так как больше нет необходимости хранить состояния страниц, чтобы их повторно воссоздавать на сервере. Нет обработчиков событий, нет ViewState, нет Drag'n'Drop контролов на форму.

Еще одна полезная особенность – нет необходимости реализовывать URL-Rewriting (использования "дружественных" и удобных ссылок, так как, например, на сайте lenta.ru: http://lenta.ru/news/2010/03/07/vision/). Для ASP.NET MVC такой подход является стандартным – весь путь определяет контроллер, который необходимо использовать на сервере (при этом последний уровень определят имя контроллера, а остальные – его месторасположение), а параметры передаются через HTTP POST.

MVC делит пользовательский интерфейс на три разных объекта: контроллер получает входные данные и обрабатывает их, модель содержит логику домена, представление оформляет полученный результат. В контексте Веб-приложений входные данные – это HTTP-запрос. Ход обработки запросов показан на рисунке.

 

 

Рис.Ход обработки запроса в схеме MVC

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

На рисунке ниже показано, как ASP.NET MVC обрабатывает запрос на высоком уровне.

Рис. Жизненный цикл запроса ASP.NET MVC

 

Маршрутизация

Весь трафик ASP.NET MVC начинается подобно трафику любого другого веб-сайта: с запроса какого-то URL. Это означает, что несмотря на отсутствие упоминания в названии, в основе каждого запроса ASP.NET MVC находится инфраструктура маршрутизации ASP.NET Routing.

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

Если механизм маршрутизации находит совпадающий шаблон в таблице маршрутизации, он перенаправляет запрос соответствующему обработчику для этого запроса.

В противном случае, если URL запроса не совпадает ни с одним из зарегистрированных шаблонов маршрутов, механизм маршрутизации указывает на то, что ему не удалось определить, как обрабатывать запрос, возвращая код состояния HTTP 404.


 

Конфигурирование маршрутов

Маршруты ASP.NET MVC отвечают за определение того, какой метод контроллера (по-другому известный как действие контроллера) выполнять для данного URL. С маршрутами связаны следующие свойства.

 Уникальное имя. Имя может использоваться в качестве специфичной ссылки на конкретный маршрут.

 Шаблон URL. Простой синтаксис шаблонов, который разбирает совпадающие URL на значащие сегменты.

 Стандартные значения. Необязательный набор стандартных значений для сегментов, определенных в шаблоне URL.

 Ограничения. Набор ограничений для применения к шаблону URL с целью более узкого определения URL, для которых он дает совпадение.

Стандартные шаблоны проектов ASP.NET MVC добавляют обобщенный маршрут, который использует приведенное ниже соглашение об URL для разбиения URL заданного запроса на три именованных сегмента, заключенных в фигурные скобки ({}): “контроллер”, “действие” и “идентификатор”: {controller}/{action}/{id}

Этот шаблон маршрута регистрируется с помощью вызова расширяющего метода MapRoute() во время запуска приложения (в App_Start/RouteConfig.cs):

routes.MapRoute(

"Default", // __ ________

"{controller}/{action}/{id}", // URL _ ___________

new { controller = "Home", action = "Index",

id = UrlParameter.Optional } // ___________ ________ __________

);

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

Например, в табл. 1.1 содержится список URL, которые совпадают с этим шаблоном маршрута, вместе с соответствующими значениями, которые инфраструктура маршрутизации предоставит каждому из них.

Первый URL (/auctions/auction/1234) в табл. 1.1 обеспечивает полное соответствие, т.к. он удовлетворяет каждому сегменту шаблона маршрута. Однако по мере того, как в последующих URL убираются сегменты, начинают применяться стандартные значения для сегментов, для которых значения явно не указаны в URL.

Это очень важный пример того, как ASP.NET MVC использует концепцию соглашения по конфигурации: во время запуска приложения ASP.NET MVC обнаруживает все контроллеры приложения, выполняя в доступных сборках поиск классов, которые реализуют интерфейс System.Web.Mvc.IController (или являются производными от класса, реализующего этот интерфейс, такого как System.Web.Mvc.Controller) и имена которых заканчиваются суффиксом Controller. Когда инфраструктура маршрутизации применяет этот список для выяснения, к каким контроллерам она имеет доступ, суффикс Controller отбрасывается из всех имен классов контроллеров.

Таким образом, для ссылки на контроллер должно использоваться сокращенное имя, например, на AuctionsController необходимо ссылаться как на Auctions, а на HomeController — как на Home.

Более того, значения контроллера и действия в маршруте не чувствительны к регистру символов. Это означает, что каждый из запросов /Auctions/Recent, /auctions/Recent, /auctions/recent или даже /aucTionS/rEceNt будет успешно преобразован в действие Recent контроллера AuctionsController.

Шаблоны маршрутов URL являются относительными корня приложения, поэтому они не должны начинаться с косой черты (/) или указателя виртуального пути (~/). Шаблоны маршрутов, которые содержат эти символы, считаются недопустимыми и приведут к генерации исключения системой маршрутизации.

 

Контроллеры

В контексте архитектурного шаблона MVC контроллер отвечает на пользовательский ввод (например, когда пользователь щелкает на кнопке Save (Сохранить)) и совместно работает с уровнями моделей, представлений и (довольно часто) доступа к данным. В приложении ASP.NET MVC контроллеры — это классы, содержащие методы, которые вызываются инфраструктурой маршрутизации для обработки запроса.

В качестве примера контроллера ASP.NET MVC рассмотрим класс HomeController, находящийся в файле Controllers/HomeController.cs:

using System.Web.Mvc;

namespace Ebuy.Website.Controllers

{

public class HomeController : Controller

{

public ActionResult Index()

{

// ________ ________ __________.

ViewBag.Message = "Your app description page.";

return View();

}

public ActionResult About()

{

// ________ ________ ________ __________.

ViewBag.Message = "Your quintessential app description page.";

return View();

}

public ActionResult Contact()

{

// ________ _________.

ViewBag.Message = "Your quintessential contact page.";

return View();

} } }

 

Действия контроллеров

Как видите, классы контроллеров не являются чем-то особенным; т.е. они не сильно по виду отличаются от других классов .NET. На самом деле всю обработку запросов выполняют методы классов контроллеров, которые называются действиями контроллеров. Например, только что рассмотренный класс HomeController содержит три действия: Index, About и Contact. Таким образом, учитывая стандартный шаблон маршрута {controller}/{action}/{id}, когда производится запрос URL вида /Home/About, инфраструктура маршрутизации определяет, что этот запрос должен быть обработан методом About() класса HomeController. Затем ASP.NET MVC Framework создает новый экземпляр класса HomeController и выполняет его метод About().

В этом случае метод About() очень прост: он передает данные представлению через свойство ViewBag (оно будет описано позже), после чего сообщает ASP.NET MVC Framework о необходимости отображения представления по имени About за счет вызова метода View(), который возвращает ActionResult типа ViewResult.

 

Результаты действий

Очень важно отметить, что работа контроллера заключается в уведомлении ASP.NET MVC Framework о том, что должно делаться следующим, но не как это должно делаться. Такое взаимодействие происходит с применением ActionResult — возвращаемых значений, которые, как ожидается, предоставляет каждое действие контроллера.

Например, когда контроллер решает отобразить представление, он сообщает ASP.NET MVC Framework об этом, возвращая ViewResult. Он не визуализирует самопредставление. Такое слабое связывание является еще одним хорошим примером реализации разделения ответственности (что делать против того, каким образом это делать).

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

_ Content(). Возвращает экземпляр ContentResult, который визуализирует произвольный текст, например, “Hello, world!”.

_ File(). Возвращает экземпляр FileResult, который визуализирует содержимое файла, например, PDF.

_ HttpNotFound(). Возвращает экземпляр HttpNotFoundResult, который визуализирует ответ в виде кода состояния HTTP 404.

_ JavaScript(). Возвращает экземпляр JavaScriptResult, который визуализирует код JavaScript, например, function hello() { alert(Hello, World!); }.

_ Json(). Возвращает экземпляр JsonResult, который сериализирует объект и визуализирует его в формате JSON (JavaScript Object Notation — нотация объектов JavaScript), например, { "Message": Hello, World! }.

_ PartialView(). Возвращает экземпляр PartialViewResult, который визуализирует только контент представления (т.е. представление без его разметки).

_ Redirect(). Возвращает экземпляр RedirectResult, который визуализирует код состояния HTTP 302 (временное перенаправление) для перенаправления пользователя к заданному URL, например, 302 http://www.ebuy.com/auctions/recent. Этот метод имеет родственный метод RedirectPermanent(), который также возвращает RedirectResult, но использует код состояния HTTP 301 для указания постоянного перенаправления, а не временного.

_ RedirectToAction() и RedirectToRoute(). Функционируют подобно вспомогательному методу Redirect(), но только инфраструктура динамически определяет внешний URL, запрашивая механизм маршрутизации. Аналогично вспомогательному методу Redirect(), эти два метода также имеют варианты постоянного перенаправления: RedirectToActionPermanent() и RedirectToRoutePermanent().

_ View(). Возвращает экземпляр ViewResult, который визуализирует представление.

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

 

Параметры действий

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

Перед тем как погружаться в детали работы привязки модели, давайте рассмотрим пример “традиционного” способа взаимодействия со значениями запроса:

public ActionResult Create()

{

var auction = new Auction() {

Title = Request["title"],

CurrentPrice = Decimal.Parse(Request["currentPrice"]),

StartTime = DateTime.Parse(Request["startTime"]),

EndTime = DateTime.Parse(Request["endTime"]),

};

// ...

}

Действие контроллера в этом конкретном примере создает и заполняет свойства нового объекта Auction значениями, полученными прямо из запроса. Поскольку некоторые свойства Auction определены как разнообразные элементарные, отличные от string типы, действию также понадобится выполнить разбор каждого из соответствующих значений запроса в подходящий тип.

Этот пример может выглядеть простым и прямолинейным, но в действительности он очень хрупкий: в случае неудачи любой попытки разбора все действие завершится сбоем. Переход к применению различных методов TryParse() может помочь избежать большинства исключений, но потребует написания дополнительного кода.

Побочным эффектом такого подхода является то, что каждое действие становится очень подробным. Недостаток написания подобного явного кода связан с тем, что на вас как разработчика возлагается бремя по выполнению всей работы каждый раз, когда это требуется. Большой объем кода также затеняет реальную цель: в настоящем примере это добавление нового объекта Auction в систему.

 

Основы привязки модели

Привязка модели не только позволяет избавиться от всего явного кода, она еще также очень проста в применении. Например, ниже приведен то же самое действие контроллера, что и ранее, но на это раз с использованием параметров метода, привязанных к модели:

public ActionResult Create(

string title, decimal currentPrice,

DateTime startTime, DateTime endTime

)

{

var auction = new Auction() {

Title = title,

CurrentPrice = currentPrice,

StartTime = startTime,

EndTime = endTime,

};// ...

}

Теперь вместо явного извлечения значений из Request действие объявляет их как параметры. Когда инфраструктура ASP.NET MVC выполняет этот метод, она пытается заполнить параметры действия, используя те же самые значения из запроса, которые были показаны в предыдущем примере. Обратите внимание, что хотя мы не обращаемся к словарю Request напрямую, имена параметров по-прежнему очень важны, т.к. они соответствуют значениям из Request. Тем не менее, объект Request — не единственное место, откуда связыватель модели получает значения. Инфраструктура производит поиск в различных местах, таких как данные маршрута, параметры строки запроса, значения отправленной формы и даже сериализированные объекты JSON. Например, в следующем фрагменте кода значение извлекается из URL просто за счет объявления параметра с тем же именем.

Фильтры действий

Фильтры действий предоставляют простой, но мощный способ модификации или расширения конвейера ASP.NET MVC за счет “внедрения” логики в определенных точках, помогая реализовать “сквозную функциональность”, которая применяется ко многим (или всем) компонентам приложения. Классическим примером сквозной функциональности является ведение журнала приложения, в равной степени применимого ко всем компонентам приложения вне зависимости от того, в чем заключается основная ответственность того или иного компонента.

Логика фильтров действий в основном вводится за счет применения атрибута ActionFilterAttribute к действию контроллера для оказания влияния на то, как выполняется это действие; это демонстрируется в следующем примере, где действие контроллера защищается от неавторизованного доступа путем применения

AuthorizeAttribute:

[Authorize]

public ActionResult Profile()

{

// ______ _________# _______ ___ ____$___ ____________.

return View();

}

 

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

В ASP.NET MVC Framework действия контроллеров, которым необходимо отобразить HTML-разметку пользователю, возвращают экземпляр ViewResult — тип ActionResult, знающий, как визуализировать контент для ответа. Когда наступает время визуализации представления, ASP.NET MVC Framework ищет представление с использованием имени, предоставленного контроллером.

Взгляните на действие Index в HomeController:

public ActionResult Index()

{

ViewBag.Message = "Your app description page.";

return View();

}

Это действие вызывает вспомогательный метод View() для создания экземпляра ViewResult. Вызов View() без параметров, как в этом примере, указывает ASP.NET MVC на необходимость поиска представления с тем же именем, что и у текущего действия контроллера. В приведенном примере ASP.NET MVC будет искать представление Index, но где именно?

 

Определение местоположения представлений

Инфраструктура ASP.NET MVC полагается на соглашение, которое заключается в том, что все представления приложения хранятся внутри папки Views в корне веб-сайта. Более конкретно, ASP.NET MVC ожидает обнаружить представления в папках, именованных согласно контроллеру, к которому они относятся. Таким образом, когда инфраструктура желает отобразить представление для действия Index в HomeController, она будет искать в папке /Views/Home файл по имени Index. Если найти представление с нужным именем в папке Views контроллера не удалось, ASP.NET MVC продолжает поиск в общей папке /Views/Shared.

Папка /Views/Shared — великолепное место для размещения представлений, разделяемых между множеством контроллеров. Теперь, когда найдено представление, запрошенное действием, откройте его и удостоверьтесь, что внутри там присутствует HTML-разметка и код. Однако это не просто любая HTML-разметка и код — это Razor!

 

Механизм Razor

Razor — это синтаксис, который позволяет комбинировать код и контент универсально. Несмотря на введение нескольких символов и ключевых слов, Razor не является новым языком. Вместо этого Razor позволяет писать код, используя известные вам языки, такие как C# или Visual Basic .NET.

Изучение Razor будет коротким, поскольку имеется возможность задействовать существующие знания, а не осваивать совершенно новый язык. Таким образом, если вы умеете разрабатывать код HTML и .NET на C#, то можете просто записать разметку вроде показанной ниже:

<div>This page rendered at @DateTime.Now</div>

Это даст следующий вывод:

<div>This page rendered at 1/29/2013 7:38:00 AM</div>

Приведенный пример начинается со стандартного HTML-дескриптора (<div>), за которым следует фрагмент “жестко закодированного” текста, порция динамического текста, визуализированная как результат ссылки на свойство .NET (System.DateTime.Now), и, наконец, закрывающий HTML-дескриптор (</div>).

Интеллектуальный анализатор Razor позволяет разработчикам более универсально представлять логику и упрощает переходы между кодом и разметкой. Хотя синтаксис Razor может отличаться от других синтаксисов разметки (таких как Web Forms), он, в конечном счете, преследует ту же самую цель: визуализацию HTML.

Для иллюстрации этого аспекта взгляните на приведенные ниже фрагменты, которые демонстрируют примеры общих сценариев, реализованных с помощью разметки Razor и Web Forms.

Вот как выглядит оператор if/else в синтаксисе Web Forms:

<% if(User.IsAuthenticated) { %>

<span>Hello, <%: User.Username %>!</span>

<% } %>

<% else { %>

<span>Please <%: Html.ActionLink("log in") %></span>

<% } %>

А вот он же, но в синтаксисе Razor:

@if(User.IsAuthenticated) {

<span>Hello, @User.Username!</span>

} else {

<span>Please @Html.ActionLink("log in")</span>

}

Цикл foreach в рамках синтаксиса Web Forms может быть записан так:

<ul>

<% foreach( var auction in auctions) { %>

40 Часть I. Начало работы

<li><a href="<%: auction.Href %>"><%: auction.Title %></a></li>

<% } %>

</ul>

В синтаксисе Razor он представляется следующим образом:

<ul>

@foreach( var auction in auctions) {

<li><a href="@auction.Href">@auction.Title</a></li>

}

</ul>

Несмотря на применение разного синтаксиса, оба фрагмента для каждого примера визуализируются в одну и ту же HTML-разметку.

 

Различение кода и разметки

Razor предоставляет два способа различения кода и разметки: фрагменты кода и блоки кода.

Фрагменты кода (code nuggets) — это простые выражения, которые оцениваются и визуализируются встроенным образом. Они могут смешиваться с текстом и выглядят примерно так:

Not Logged In: @Html.ActionLink("Login", "Login")

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

Показанный выше пример визуализирует следующий вывод:

Not Logged In: <a href="/Login">Login</a>

Обратите внимание, что фрагменты кода должны всегда возвращать разметку для визуализации представлением. Если вы напишете фрагмент кода, который оценивается как значение void, то получите ошибку при выполнении представления.

Блок кода (code block) — это раздел представления, который содержит строго код, а не комбинацию разметки и кода. Блоки кода в Razor определяются как любой раздел шаблона Razor, помещенный внутрь символов @{ }. Символы @{ помечают начало блока, за которым следует любое количество строк полноценно сформированного кода. Символ } закрывает блок кода.

Имейте в виду, что код внутри блока кода не похож на код внутри фрагмента кода. Это обычный код, который должен следовать правилам текущего языка. Например, каждый оператор кода на языке C# должен завершаться точкой с запятой (;), как если бы он находился внутри класса в файле .cs.

Ниже приведен пример типичного блока кода:

@{

LayoutPage = "~/Views/Shared/_Layout.cshtml";

View.Title = "Auction " + Model.Title;

}

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

Кроме того, переменные, которые определены в блоках кода, могут использовать ся фрагментами кода, находящимися в той же области видимости. Это значит, что переменные, определенные внутри цикла foreach или аналогичного контейнера, будут доступны только в рамках этого контейнера. С другой стороны, переменные, которые определены на верхнем уровне представления (за пределами любого вида контейнера), будут доступны любым другим блокам кода или фрагментам кода в том же представлении.

Чтобы прояснить сказанное, рассмотрим представление с несколькими переменными, определенными в различных областях видимости:

@{

// _________ title _ bids ________ __ _____ ____________#.

var title = Model.Title;

var bids = Model.Bids;

}

<h1>@title<h1>

<div class="items">

<!-- &___ __ _'*_____ _ _________ bids -->

@foreach(var bid in bids) {

<!-- _________ bid ________ ______ ______ _____ foreach -->

<div class="bid">

<span class="bidder">@bid.Username</span>

<span class="amount">@bid.Amount</span>

</div>

}

<!-- 5__ ________ _ ___'__: __________ bid __ __$_______ _ 6__          

_'_____ _________! -->

<div>Last Bid Amount: @bid.Amount</div>

</div>

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

 

Компоновки

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

Шаблон компоновки обычно включает главную разметку (сценарии, таблицы стилей CSS и структурированные HTML-элементы, такие как контейнеры навигации и контента), указывающую местоположения внутри компоновки, в которых представления могут определять контент. Каждое представление на сайте затем ссылается на эту компоновку, добавляя со своей стороны только контент в заданные местоположения.

Взгляните на базовый файл компоновки Razor (_Layout.cshtml):

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8" />

<title>@View.Title</title>

</head>

42 Часть I. Начало работы

<body>

<div class="header">

@RenderSection("Header")

</div>

@RenderBody()

<div class="footer">

@RenderSection("Footer")

</div>

</body>

</html>

Этот файл компоновки содержит главный HTML-контент, определяющий структуру HTML-разметки для всего сайта. Для взаимодействия с отдельными представлениями в компоновке используются переменные (такие как @View.Title) и вспомогательные функции наподобие @RenderSection([__?______]) и @RenderBody().

После определения компоновки Razor представления ссылаются на эту компоновку и поставляют контент для ее разделов.

Ниже приведена базовая страница контента, которая ссылается на ранее определенный файл _Layout.cshtml:

@{ Layout = "~/_Layout.cshtml"; }

@section Header {

<h1>EBuy Online Auction Site<h1>

}

@section Footer {

Copyright @DateTime.Now.Year

}

<div class="main">

This is the main content.

</div>

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

 

Частичные представления

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

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

Например, сайт онлайновых аукционов Ebuy может визуализировать список кратких сведений о продаваемых предметах (содержащих только название, текущую цену и, возможно, миниатюрное изображение предмета) во многих местах на сайте, среди которых страница результатов поиска и список популярных предметов на домашней странице сайта.

Инфраструктура ASP.NET MVC поддерживает сценарии подобного рода через частичные представления. Частичные представления — это такие представления, которые содержат целевую разметку, предназначенную для визуализации в виде части более крупного представления. В следующем фрагменте демонстрируется частичное представление для отображения кратких сведений о продаваемых предметах, которые упоминались выше:

@model Auction

<div class="auction">

<a href="@Model.Url">

<img src="@Model.ImageUrl" />

</a>

<h4><a href="@Model.Url">@Model.Title</a></h4>

<p>Current Price: @Model.CurrentPrice</p>

</div>

Чтобы визуализировать этот фрагмент как частичное представление, просто сохраните его в отдельном файле представления (например, /Views/Shared/Auction.cshtml) и воспользуйтесь одним из вспомогательных методов HTML инфраструктуры ASP.NET MVC — Html.Partial() — для визуализации представления в виде части другого представления.

Рассмотрим сказанное в действии. Ниже показан фрагмент, в котором производится проход по коллекции объектов, продающихся на аукционе, с применением приведенного выше частичного представления для визуализации HTML-разметки по каждому предмету:

@model IEnumerable<Auction>

<h2>Search Results</h2>

@foreach(var auction in Model) {

@Html.Partial("Auction", auction)

}

Обратите внимание, что первым параметром вспомогательного метода Html.Partial() является строка, содержащая имя представления без расширения. Причина в том, что вспомогательный метод Html.Partial() — всего лишь простой уровень, определенный поверх мощного механизма представлений ASP.NET MVC.

Данный метод визуализирует представление почти так же, как это происходит в ситуации, когда действие контроллера вызывает метод View() для возврата ActionResult типа ViewResult: механизм использует имя представления для нахождения и выполнения соответствующего представления.

При таком подходе частичные представления разрабатываются и выполняются в основном подобно любой другой разновидности представлений. Единственное отличие состоит в том, что они предназначены для визуализации в качестве части более крупного представления.

Второй параметр (auction в рассмотренном выше примере) принимает модель частичного представления, в точности как параметр модели во вспомогательном методе контроллера View(______________, [______]). Этот второй параметр модели является необязательным; если он не указан, то по умолчанию будет применяться модель представления, из которого был вызван метод Html.Partial(). Например, если в предыдущем примере второй параметр auction опустить, ASP.NET MVC будет передавать на его месте значение свойства Model (типа IEnumerable<Auction>) представления.

 

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

 

Отображение данных

Архитектура MVC зависит от модели, представления и контроллера, которые все остаются отдельными, но работают вместе для достижения общей цели. В этом отношении задача контроллера — выступать в качестве “регулятора движения”, координируя разнообразные части системы для выполнения логики приложения. Результатом такой обработки обычно является определенный вид данных, которые должны быть переданы пользователю. Тем не менее, отображение их пользователю не входит в ответственность контроллера — для этого предназначены представления. В таком случае возникает вопрос: каким образом контроллер передает эту информацию представлению?

Инфраструктура ASP.NET MVC предлагает два способа передачи данных в рамках границ “модель-представление-контроллер”: ViewData и TempData. Эти объекты являются словарями, доступными в виде свойств в контроллерах и представлениях. Таким образом, передача данных из контроллера в представление сводится к установке значения в контроллере, как показано в следующем фрагменте кода из HomeController.cs:

public ActionResult About()

{

ViewData["Username"] = User.Identity.Username;

ViewData["CompanyName"] = "EBuy: The ASP.NET MVC Demo Site";

ViewData["CompanyDescription"] =

"EBuy is the world leader in ASP.NET MVC demoing!";

return View("About");

}

и последующей ссылке на значение в представлении, что видно в части кода, взятой из файла About.cshtml:

<h1>@ViewData["CompanyName"]</h1>

<div>@ViewData["CompanyDescription"]</div>

 

Строго типизированные представления

По умолчанию свойство Model, доступное внутри представлений Razor, является динамическим (dynamic), а это означает, что получать доступ к его значениям можно, не зная точный тип.

Тем не менее, учитывая статическую природу языка C# и великолепную поддержку средства IntelliSense для представлений Razor в Visual Studio, часто удобнее указывать тип модели страницы явным образом. К счастью, Razor позволяет делать это очень просто — нужно лишь воспользоваться ключевым словом @model для указания имени типа модели:

@model Auction

<h1>@Model.Name</h1>

<div>@Model.Description</div>

Этот фрагмент модифицирует предыдущий пример Auction.cshtml, устраняя необходимость в добавлении промежуточной переменной для приведения ViewData.Model. Вместо этого в первой строке с помощью ключевого слова @model указывается, что типом модели является CompanyInfo, и это делает все ссылки на ViewData.Model строго типизированными и доступными напрямую.

 

Вспомогательные методы HTML и URL

Основная цель большинства веб-запросов заключается в доставке HTML-разметки пользователю, и ASP.NET MVC оказывает помощь в создании HTML. Помимо языка разметки Razor, инфраструктура ASP.NET MVC также предлагает множество вспомогательных классов и методов для простой и эффективной генерации HTML-разметки.

Двумя самыми важными вспомогательными классами являются HtmlHelper и UrlHelper, которые доступны в контроллерах и представлениях через свойства Html и Url.

Вот пример применения этих двух вспомогательных классов:

<img src='@Url.Content("~/Content/images/header.jpg")' />

@Html.ActionLink("Homepage", "Index", "Home")

Визуализированная разметка выглядит следующим образом:

<img src='/vdir/Content/images/header.jpg' />

<a href="/vdir/Home/Index">Homepage</a>

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

В данный момент следует также отметить один момент: класс HtmlHelper помога-ет генерировать HTML-разметку, а класс UrlHelper оказывает помощь в генерации URL. Имейте это в виду и обращайтесь к упомянутым вспомогательным классам всегда, когда требуется генерировать URL или HTML._

Мы рассмотрели представления (view) и контроллеры (control). Модель – это набор классов данных, использующая представления и контроллеры. Более подробно модели рассмотрим на практическом занятии.

 

2. Структура проекта ASP.NET MVC 5

При создании нового проекта ASP.NET среда Visual Studio предоставляет несколько вариантов первоначального содержимого, которое требуется для проекта. Идея состоит в том, чтобы упростить процесс изучения разработчикам-новичкам и применить экономящие время рекомендуемые приемы для распространенных средств и задач. Такая поддержка воплощена через шаблоны, используемые для создания контроллеров и представлений, которые создаются с помощью шаблонного кода для вывода списков объектов данных, редактирования свойств модели и т.д.

Создание проекта

Когда вы впервые создаете новый проект MVC Framework, у вас есть на выбор две базовых отправных точки: шаблон Empty (Пустой) и шаблон MVC. Эти имена несколько обманчивы, т.к. добавить базовые папки и сборки, требуемые для MVC Framework, можно в любой проект, отметив флажок MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для) диалогового окна New ASP.NET Project.

Реальное отличие связано с дополнительным содержимым, которое шаблон MVC добавляет в новые проекты. Оно предоставляет готовую отправную точку, включающую стандартные контроллеры и представления, конфигурацию безопасности, ряд популярных пакетов JavaScript и CSS (таких как jQuery и Bootstrap), а также компоновку - которая применяет библиотеку Bootstrap для построения темы, оформляющей пользовательский интерфейс приложения.

 

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



  

© helpiks.su При использовании или копировании материалов прямая ссылка на сайт обязательна.