Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP_NET_MVC_4_Framework_s_primerami_na_C_dlya_p

.pdf
Скачиваний:
25
Добавлен:
19.03.2016
Размер:
17.66 Mб
Скачать

содержащиеся в базе данных. В листинге 11-13 показан метод, который мы добавили в класс

ProductController.

Листинг 11-13: Метод действия GetImage

public FileContentResult GetImage(int productId)

{

Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); if (prod != null)

{

return File(prod.ImageData, prod.ImageMimeType);

}

else

{

return null;

}

}

Этот метод пытается найти товар, который соответствует указанному в параметре ID. Он возвращает класс FileContentResult, когда мы хотим вернуть файл браузеру клиента, и экземпляры создаются с помощью метода File базового класса контроллера. Мы обсудим различные типы результатов, которые можно возвращать из методов действий, в главе 15.

Модульный тест: получение изображений

Мы хотим убедиться, что метод GetImage возвращает из хранилища правильный тип MIME, и гарантировать, что данные не возвращаются, если мы запрашиваем несуществующий ID товара. Вот тестовые методы, которые мы добавили в новый файл тестов под названием ImageTests.cs:

using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq;

using SportsStore.Domain.Abstract; using SportsStore.Domain.Entities; using SportsStore.WebUI.Controllers; using System.Linq;

using System.Web.Mvc; namespace SportsStore.UnitTests

{

[TestClass]

public class ImageTests

{

[TestMethod]

public void Can_Retrieve_Image_Data()

{

//Arrange - create a Product with image data Product prod = new Product

{

ProductID = 2, Name = "Test",

ImageData = new byte[] { }, ImageMimeType = "image/png"

};

//Arrange - create the mock repository Mock<IProductRepository> mock = new Mock<IProductRepository>(); mock.Setup(m => m.Products).Returns(new Product[] {

new Product {ProductID = 1, Name = "P1"}, prod,

new Product {ProductID = 3, Name = "P3"} }.AsQueryable());

//Arrange - create the controller

ProductController target = new ProductController(mock.Object); // Act - call the GetImage action method

281

ActionResult result = target.GetImage(2); // Assert

Assert.IsNotNull(result); Assert.IsInstanceOfType(result, typeof(FileResult));

Assert.AreEqual(prod.ImageMimeType, ((FileResult)result).ContentType);

}

[TestMethod]

public void Cannot_Retrieve_Image_Data_For_Invalid_ID()

{

//Arrange - create the mock repository Mock<IProductRepository> mock = new Mock<IProductRepository>(); mock.Setup(m => m.Products).Returns(new Product[] {

new Product {ProductID = 1, Name = "P1"}, new Product {ProductID = 2, Name = "P2"}

}.AsQueryable());

//Arrange - create the controller

ProductController target = new ProductController(mock.Object);

//Act - call the GetImage action method ActionResult result = target.GetImage(100);

//Assert

Assert.IsNull(result);

}

}

}

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

Теперь администратор может загружать изображения для товаров. Вы можете попробовать сделать это сами, запустив приложение, перейдя по ссылке в /Admin/Index и отредактировав один из товаров. Пример показан на рисунке 11-6.

Рисунок 11-6: Добавляем изображение к списку товаров

282

Выводим изображения товаров

Теперь нам остается только визуализировать изображения рядом с описаниями товаров в каталоге. Отредактируйте представление Views/Shared/ProductSummary.cshtml и внесите в него изменения, выделенные жирным шрифтом в листинге 11-14.

Листинг 11-14: Отображаем изображения в каталоге товаров

@model SportsStore.Domain.Entities.Product <div class="item">

@if (Model.ImageData != null) {

<div style="float: left; margin-right: 20px">

<img width="75" height="75" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />

</div>

}

<h3>@Model.Name</h3>

@Model.Description <div class="item">

@using (Html.BeginForm("AddToCart", "Cart")) { @Html.HiddenFor(x => x.ProductID) @Html.Hidden("returnUrl", Request.Url.PathAndQuery) <input type="submit" value="+ Add to cart" />

}

</div>

<h4>@Model.Price.ToString("c")</h4>

</div>

Когда эти изменения применены, пользователи при просмотре каталога будут видеть изображения как часть описания товара, как показано на рисунке 11-7.

Рисунок 11-7: Выводим изображения товаров

283

Резюме

Вэтой и предыдущих главах мы продемонстрировали, как с помощью ASP.NET MVC Framework можно создать реалистичное приложение для электронной коммерции. В этом расширенном примере мы рассмотрели многие ключевые возможности платформы: контроллеры, методы действий, маршрутизацию, представления, связывание данных, метаданные, валидацию, макеты, аутентификацию и многое другое. Вы также видели, как можно использовать такие важные технологии, связанные с MVC, как Entity Framework, Ninject, MOQ и поддержка модульного тестирования в Visual Studio.

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

284

ASP.NET MVC 4 в деталях

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

Вчасти 2 этой книги мы подробно рассмотрим механизм фреймворка. Мы начнем с изучения структуры ASP.NET MVC приложения и способа, которым обрабатываются запросы. Затем сосредоточимся на отдельных функциях, таких как маршрутизация (главы 13 и 14), контроллеры и методы действий (главы 15-17), MVC представления и система вспомогательных методов (главы 1821), и на том, как MVC работает с доменной моделью (главы 22 и 23).

Впоследних главах этой книги мы покажем вам возможности MVC, которые упрощают разработку на стороне клиента (главы 24 и 25), а также мы расскажем, как подготовить и развернуть MVC приложение (глава 26).

Обзор MVC проектов

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

Работа с MVC проектами Visual Studio

Когда вы создаете новый MVC проект, Visual Studio дает вам возможность выбора между различными отправными точками: Empty, Basic, Internet Application, Intranet Application, Mobile Application и Web API, как показано на рисунке 12-1.

Рисунок 12-1: Выбор начальной конфигурации MVC проекта

285

Мы уже показали вам первые два шаблона в предыдущих главах. Шаблон проекта Empty мы использовали в главе 2 для приложения RSVP. Он содержит только необходимый минимум файлов, необходимых для MVC фреймворка.

Мы использовали шаблон проекта Basic в главе 7, когда мы создали приложение SportsStore. Его структура дополнена, по сравнению с шаблоном Empty, некоторыми макетами, файлами JavaScript и некоторыми CSS стилями, используемыми для элементов HTML форм и валидации. Шаблон Basic мы используем в наших собственных проектах, потому что скриптовые файлы и другие дополнения полезны, но мы все же можем сами реализовывать важные части проекта, как мы делали для приложения SportsStore.

Шаблоны Internet Application и Intranet Application заполнены более полно, тут используются различные механизмы аутентификации, которые подходят для интернет и интранет приложений. Шаблон Mobile Application является вариацией шаблона Internet Application, и он оптимизирован для мобильных устройств (мы объясним новые функции MVC 4 для мобильных устройств в главе 24). И, наконец, шаблон Web API создает проект, который поможет вам начать работу с новой MVC 4 Web API функцией, которую мы объясним в главе 25.

Вы можете увидеть разницу между тремя из этих шаблонов на рисунке 12-2, где мы показали содержимое Solution Explorer для шаблонов Basic, Internet Application и Intranet Application.

Рисунок 12-2: Начальное содержание, созданное шаблонами Empty, Internet Application и Intranet Application

286

Вы видите, что проект Internet Application является самым сложным, это потому что он реализует всю систему пользовательской аутентификации, которая требует много различных представлений. Проект Intranet Application может работать с Windows аутентификацией для обработки задач, связанных, например, со сменой пароля. А шаблон Basic по умолчанию вообще не обеспечивает аутентификацию.

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

Какой бы шаблон вы ни выбрали, вы заметите, что в результате у проектов очень похожие структуры. Некоторые из элементов MVC проекта имеют особые роли, они жестко вписаны в ASP.NET или MVC фреймворк. Другие затрагивают соглашение по именам. Мы описали каждый из этих файлов и папок в таблице 12-1.

Таблица 12-1: Элементы MVC проекта

Папка или файл

 

Описание

 

 

В эту папку вы кладете закрытые данные,

 

 

/App_Data

 

такие как XML-файлы или базы данных,

 

если вы используете SQL Server Express,

 

 

 

 

SQLite или другие файловые хранилища.

 

 

В этой папке содержатся некоторые

 

 

/App_Start

 

основные параметры конфигурации для

 

вашего проекта, в том числе определение

 

 

 

 

роутов, фильтры, связки.

 

 

Здесь размещается скомпилированная

 

 

/bin

 

сборка для вашего MVC приложения,

 

наряду с любыми связанными сборками,

 

 

 

 

которые не в GAC.

 

 

 

Примечание

IIS не будет обрабатывать содержимое этой папки.

Мы описываем роуты в главе 13, фильтры в главе 16 и связки в главе

24.

IIS не будет обрабатывать содержимое этой директории. Вы не увидите bin директорию в окне

Solution Explorer, пока не нажмете кнопку Show All Files. Поскольку это бинарные файлы, созданные при компиляции, вам обычно не следует хранить их в системе управления.

/Content

/Controllers

/Models

/Scripts

Здесь вы храните статический контент, как CSS стили и рисунки.

Здесь хранятся классы контроллеров.

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

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

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

Это соглашение. Вы можете определить классы модели в любом месте проекта или в отдельном проекте.

В этой директории содержатся JavaScript

 

Это соглашение. Вы можете

библиотеки для вашего проекта. Visual

 

поместить скриптовые файлы в

287

 

 

Папка или файл

 

Описание

 

Примечание

 

 

 

 

 

 

 

Studio добавляет jQuery и некоторое

 

любом месте, так как они в

 

 

другие популярные библиотеки.

 

действительности являются просто

 

 

 

 

еще одним типом статического

 

 

 

 

контента. См. главу 24 для получения

 

 

 

 

дополнительной информации об

 

 

 

 

управлении скриптовыми файлами.

/Views

/Views/Shared

/Views/Web.config

/Global.asax

/Web.config

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

Вэтой директории содержатся макеты и представления, которые не являются конкретными для отдельного контроллера.

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

Это глобальный класс ASP.NET приложения. Его класс с выделенным кодом (Global.asax.cs) является местом для регистрации настройки маршрутизации, а также настройки любого кода для запуска при инициализации приложения или завершении работы, а также при получении необработанных исключений.

Файл /Views/Web.config не дает IIS

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

Файл Global.asax играет такую же роль в MVC приложениях, как и в приложениях Web Forms.

Это конфигурационный файл для вашего

 

Файл Web.config играет такую же

приложения. Мы лучше поясним его роль

 

роль в MVC приложениях, как и в

далее в этой главе.

 

приложениях Web Forms.

В таблице 12-2 представлены файлы и папки, которые имеют особенное значение, если они присутствуют в MVC проекте.

Таблица 12-2: Дополнительные элементы MVC проекта

Папка или файл

Описание

 

 

 

Области (areas) являются одним из способов разбития больших

/Areas

приложений на более мелкие куски. Мы расскажем об областях в

 

главе 13.

/App_GlobalResources, /App_LocalResources

/App_Browsers

В них хранятся исходные файлы, используемые для локализации страниц Web Forms.

Эта папка содержит XML файлы .browser, которые описывают, как

288

Папка или файл

Описание

 

 

 

идентифицировать определенные веб-браузеры, и на что способны

 

эти браузеры (например, поддерживают ли они JavaScript).

 

 

 

Эта папка содержит темы Web Forms (в том числе файлы .skin),

/App_Themes

которые влияют на то, как отображаются элементы управления Web

 

Forms.

Примечание

За исключением /Areas, элементы в таблице 12-2 являются частью ядра

платформы ASP.NET и не особенно актуальны для MVC приложений. Адам рассказывает об основных функциях ASP.NET в своих книгах Applied ASP.NET 4.5 in Context и Pro ASP.NET 4.5, опубликованных Apress.

Понимание MVC соглашений

Есть два вида соглашений для MVC проектов. Первое из них – это действительно только предложение о том, как вы можете структурировать проект. Например, по соглашению JavaScript файлы размещаются в папке Scripts. Это место, где другие MVC разработчики в первую очередь будут их искать, а также именно сюда Visual Studio помещает исходные файлы JavaScript для нового MVC проекта. Но вы можете переименовать папку Scripts или удалить ее полностью и сохранять ваши скрипты где угодно. Это не помешает MVC фреймворку запускать приложение.

Другой вид соглашения вытекает из принципа соглашения о конфигурации, которое было одним из основных пунктов продажи, сделавшим Ruby on Rails таким популярным. Соглашение о конфигурации означает, что вам не нужно, например, явно настраивать связь между контроллерами и представлениями. Вы просто следуете определенным именованиям для ваших файлов, и все работает. Тут существует меньше гибкости в изменении структуры проекта, если вы имеете дело с таким соглашением. О соглашениях более подробно рассказывается в следующих разделах.

Совет

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

Следуя соглашениям для классов контроллеров

Классы контроллеров должны иметь имена, которые заканчиваются на Controller, например,

ProductController, AdminController и HomeController.

При обращении к контроллеру из другой части проекта, например, при использовании вспомогательного метода, необходимо указать первую часть имени (как Product), а MVC фреймворк автоматически добавит к имени Controller и начинает искать класс контроллера.

289

Совет

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

Следуя соглашениям для представления

Представления и частичные представления находятся в папке /Views/Controllername. Например, представление, связанное с ProductController, будет находиться в папке /Views/Product.

Совет

Обратите внимание, что мы опускаем часть класса Controller из папки Views: мы используем папку /Views/Product, а не /Views/ProductController. Это может

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

MVC фреймворк ожидает, что представление по умолчанию для метода действия должно быть названо после этого метода. Например, представление по умолчанию, связанное с методом действия List следует называть List.cshtml. Таким образом ожидается, что для метода действия List в классе ProductController представление по умолчанию будет называться

/Views/Product/List.cshtml.

Представление по умолчанию используется, если вы возвращаете в методе действия результат вызова метода View:

return View();

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

return View("MyOtherView");

Обратите внимание, что мы не включаем расширение имени файла или путь к представлению. При поиске представления MVC фреймворк смотрит в папку с именем контроллера, а затем в папку /Views/Shared. Это означает, что мы можем хранить представления, которые будут использоваться более чем одним контроллером, в папке /Views/Shared, и фреймворк их найдет.

Следуя соглашениям для макетов

Соглашение по именованиям для макетов заключается в том, что перед именем файла стоит знак подчеркивания (_), а файлы макетов помещаются в папку /Views/Shared. Visual Studio создает макет _Layout.cshtml, если используется любой шаблон, кроме Empty. Этот макет применяется ко всем представлениям по умолчанию через файл /Views/_ViewStart.cshtml.

Если вы не хотите, чтобы макет по умолчанию применялся ко всем представлениям, вы можете изменить настройки в _ViewStart.cshtml (или полностью удалить файл), чтобы указать другой макет для представления:

@{

Layout = "~/Views/Shared/MyLayout.cshtml";

}

290

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]