ASP.NET MVC: История одного проекта "Готовимся к старту" (часть 1)

ru-RU | создано: 25.04.2012 | опубликовано: 25.04.2012 | обновлено: 02.01.2018 | просмотров за всё время: 438766

Этой статьей я хочу начать цикл, который будет рассказывать о том,как сделать свой сайт на ASP.NET MVC 3. Разработка затронет все основные этапы от проектирования до публикации.

Содержание

ASP.NET MVC: История одного проекта "Готовимся к старту" (часть 1)
ASP.NET MVC: История одного проекта "Всё ради данных" (часть 2)
ASP.NET MVC: История одного проекта "Шаблоны и внешний вид" (часть 3)
ASP.NET MVC: История одного проекта "Еще немного классов" (часть 4)
ASP.NET MVC: История одного проекта "UI - всё для пользователя" (часть 5)
ASP.NET MVC: История одного проекта "UI - Добавление экспоната" (часть 6)
ASP.NET MVC: История одного проекта "UI - Редактирование экспоната" (часть 7)
ASP.NET MVC: История одного проекта "Обработка ошибок" (часть 8)
ASP.NET MVC: История одного проекта "Фильтрация" (часть 9)
ASP.NET MVC: История одного проекта "Поиск" (часть 10)
ASP.NET MVC: История одного проекта "Облако тегов" (часть 11)
ASP.NET MVC: История одного проекта "Главная страница" (часть 12)

Историческая справка

В стародавние времена, когда NET Framework стоял у своих истоков, а я писал код исключительно на Pascal'e... Хм... кажется, так слишком долго получается, поэтому упрощу схему описания. Когда начинался сайт www.calabonga.com он был простым до безобразия. Со временем пришлось его использовать как тестовую площадку для реализации идей применимых на других сайта изготавливаемых на заказ. По прошествию некоторого количества лет сайт с юмором превратился в мусорку (до недавнего времени такое название и красовалось в заголовке). Пришло время переделать сайт, причем использую нововведения в сфере разработки под web и в частности ASP.NET MVC. Я буду использовать ASP.NET 3 потому что не хочется связываться с ASP.NET 4 Beta в силу опять же beta параметра в версии. Просто скажу, что в проекте, который работаю на работе, слишком много недочетов и недоделок в этой версии.

Инструменты

Итак, раз уж пошел разговор про инспользуемые инструменты, перечислю их:

  • Visual Studio 2010 Ultimate
  • Nuget Manager
  • ASP.NET MVC 3
  • MvcScaffolding
  • EntityFramework 4.3.1 Code First
  • Unity for MVC

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

Начало

Создаю новый проект под названием Calabonga.Mvc.Humor в параметрах MVC выбираю Internet Application и движок Razor.

Запускаю... Компилируется... Работает... Красота.

Выбор jQuery UI

Выбрал цветовую схему на сайте www.jqueryui.com чтобы проще было в дальнейшем управлять дизайном. Выбрал такую цветовую гамму:

Подключу ее немного позже, когда потребуется.

На сколько свежий ты, товарищ?

Перед тем как приступить к разработке классов для моего нового обновляемого сайта, сначала обновлю все nuget-пакеты. Для этого в в панеле nuget-менеджера введу комманду:

PM> update-package

Выполнение команды обновления можно видеть на логе консоли:

PM> Update-Package
Updating 'Modernizr' from version '1.7' to '2.5.3' in project 'Calabonga.Mvc.Humor'.
Successfully removed 'Modernizr 1.7' from Calabonga.Mvc.Humor.
Successfully installed 'Modernizr 2.5.3'.
Successfully added 'Modernizr 2.5.3' to Calabonga.Mvc.Humor.
Successfully uninstalled 'Modernizr 1.7'.
Updating 'jQuery.vsdoc' from version '1.5.1' to '1.6' in project 'Calabonga.Mvc.Humor'.
Successfully removed 'jQuery.vsdoc 1.5.1' from Calabonga.Mvc.Humor.
Successfully removed 'jQuery.UI.Combined 1.8.11' from Calabonga.Mvc.Humor.
Successfully installed 'jQuery.UI.Combined 1.8.19'.
Successfully added 'jQuery.UI.Combined 1.8.19' to Calabonga.Mvc.Humor.
Successfully removed 'jQuery.Validation 1.8.0' from Calabonga.Mvc.Humor.
Successfully installed 'jQuery.Validation 1.8.1'.
Successfully added 'jQuery.Validation 1.8.1' to Calabonga.Mvc.Humor.
Successfully removed 'jQuery 1.5.1' from Calabonga.Mvc.Humor.
Successfully installed 'jQuery 1.7.2'.
Successfully added 'jQuery 1.7.2' to Calabonga.Mvc.Humor.
IntelliSense JS files are not supported by your version of VS:  10.0
Successfully installed 'jQuery.vsdoc 1.6'.
Successfully added 'jQuery.vsdoc 1.6' to Calabonga.Mvc.Humor.
Successfully uninstalled 'jQuery.vsdoc 1.5.1'.
Successfully uninstalled 'jQuery.UI.Combined 1.8.11'.
Successfully uninstalled 'jQuery.Validation 1.8.0'.
Successfully uninstalled 'jQuery 1.5.1'.
Updating 'jQuery.Validation' from version '1.8.1' to '1.9' in project 'Calabonga.Mvc.Humor'.
Successfully removed 'jQuery.Validation 1.8.1' from Calabonga.Mvc.Humor.
Successfully installed 'jQuery.Validation 1.9'.
Successfully added 'jQuery.Validation 1.9' to Calabonga.Mvc.Humor.
Successfully uninstalled 'jQuery.Validation 1.8.1'.
No updates available for 'jQuery.UI.Combined' in project 'Calabonga.Mvc.Humor'.
No updates available for 'jQuery' in project 'Calabonga.Mvc.Humor'.
Updating 'EntityFramework' from version '4.1.10331.0' to '4.3.1' in project 'Calabonga.Mvc.Humor'.
Successfully removed 'EntityFramework 4.1.10331.0' from Calabonga.Mvc.Humor.
You are downloading EntityFramework from Microsoft, the license agreement to which is available 
at http://go.microsoft.com/fwlink/?LinkId=242868. Check the package for additional dependencies,
which may come with their own license agreement(s). Your use of the package and dependencies
constitutes your acceptance of their license agreements. If you do not accept the license agreement(s),
then delete the relevant components from your device.
Successfully installed 'EntityFramework 4.3.1'.
Successfully added 'EntityFramework 4.3.1' to Calabonga.Mvc.Humor.
Successfully uninstalled 'EntityFramework 4.1.10331.0'.

PM>

Теперь немного полезных утилит

Я добавлю пару пакетов. Один пакет называется MvcTools,  второй - PagerListExt. Устанавливаю:

PM> Install-Package MvcTools
Attempting to resolve dependency 'XmlExport (? 0.2.1)'.
Successfully installed 'XmlExport 0.2.1'.
Successfully installed 'MvcTools 1.3.0'.
Successfully added 'XmlExport 0.2.1' to Calabonga.Mvc.Humor.
Successfully added 'MvcTools 1.3.0' to Calabonga.Mvc.Humor.

PM> Install-Package PagedListExt
Successfully installed 'PagedListExt 0.5.1'.
Successfully added 'PagedListExt 0.5.1' to Calabonga.Mvc.Humor.

PM>

Что это за пакеты, и для чего они нужны, я постараюсь подробно рассказать в ходя процесса разработки сайта "Музей юмора". Итак, после обновления и установки дополнительных nuget-пакетов мой структура моего проекты выглядит следующим образом:

Наведем порядок. Для этого надо удалить старый файл шаблона _Layout.cshtml, а новый прописать на использование по умолчанию в файле _ViewStart.cshtml:

@{
    Layout = "~/Views/Shared/_LayoutExtended.cshtml";
}

Перед тем как запусть проект на компиляцию, надо в файле _LayoutExtended.cshtml поправить версии файлов скриптов и каскадных таблиц в соответствии с обновления полученными в результате работы команды Update-Package. У меня на момент написания статьи версии получились такие:

@Content.Scripts("jquery-1.7.2.min.js", Url)
@Content.Scripts("jquery.unobtrusive-ajax.min.js", Url)
@Content.Scripts("modernizr-2.5.3.js", Url)
@Content.Scripts("jquery-ui-1.8.19.custom.min.js", Url)
@RenderSection("scripts", false)
@Html.WriteScriptBlocks()

Обратите внимание на строку кода, который подключает скрипт от jquery-ui-1.8.19.custom.min.js (jQuery UI), следует добавить в проект файл этого скрипта. Да и каскадые стили тоже в папку /content/theme. Как я уже упоминал, дизайном я займусь позже, а скрипты и css-файлы надо всё-таки добавить в проект - мешать не будут. Запускаю проект... Главная страница показалась - уже хорошо! Кликаю на LogIn - получаю ошибку, что jQuery не найден. К счастью, я знаю почему так получилось поэтому поведаю и вам. Надо обернуть на странице (View) Login.cshtml скрипты в специальный тег, который появился после установки MvcTools.

Вместо:

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Должно быть:

@section scripts{
  @Content.Scripts("jquery.validate.min.js", Url)
  @Content.Scripts("jquery.validate.unobtrusive.min.js", Url)
}

Почему и зачем так сделано, можно посмотреть в сгенерирумом HTML-коде после запуска сайта. Теперь все скрипты помещаются после основного HTML перед самым закрывающим тегом </body>. А значит, что скрипты не начнут своё выполнение до того как будет загружен документ (DOM). Подробно об этом в статье на эту тему (если кому будет интересно). 

POCO классы или где же модель?

Если речь идет о Code First, что уже означает "сначала код", то надо уже подумать о моделях (классы) которые будут использованы в приложении. Я пишу сайт, который называется "музей юмора", отсюда и название классов:

/// <summary>
/// Зал музея, в музее же есть залы, где располагаются разные экспонаты
/// </summary>
public class Hall {
  public int Id { get; set; }
  public string Name { get; set; }
}
/// <summary>
/// Экспонат музея
/// </summary>
public class Exhibit {
  public int Id { get; set; }
  public DateTime CreatedAt { get; set; }
  public DateTime UpdatedAt { get; set; }
  public string Title { get; set; }
  public string Content { get; set; }
  public int TotalViewCount { get; set; }
  public int PeridViewCount { get; set; }
}

Два последних свойства в классе экпоната нужны для статистики просмотров за период и за всё время. Добавим несколько свойств для навигации (navigation properties). В классе Hall:

public virtual ICollection<Exhibit> Exhibits { get; set; }

И еще парочку в классе Exhibit:

public virtual Hall Hall { get; set; }
public int HallId { get; set; }

Теперь немного аттрибутов на свойства и будет готова первая версия модели базы данных. Для этого надо добавить namespace  System.ComponentModel.DataAnnotations в список используемых. Вот так теперь выглядят классы:

/// <summary>
/// Зал музея, в музее же есть залы, где располагаются разные экспонаты
/// </summary>
public class Hall {
  /// <summary>
  /// Иденификатор
  /// </summary>
  [Key]
 
  public int Id { get; set; }
  /// <summary>
  /// Наименование зала
  /// </summary>
  [Display(Name = "Наименование зала")]
  [Required(ErrorMessage = "Наименование зала - обязательно поле")]
  [StringLength(50, ErrorMessage = "Наименование зала не может длиннее 50 символов")]
  public string Name { get; set; }
 
  /// <summary>
  /// Коллекция экспонатов
  /// </summary>
  [Display(Name = "Коллекция экспонатов")]
  public virtual ICollection<Exhibit> Exhibits { get; set; }
}
 
/// <summary>
/// Экспонат музея
/// </summary>
public class Exhibit {
  /// <summary>
  /// Идентификатор
  /// </summary>
  [Key]
  [Display(Name = "Идентификатор")]
  public int Id { get; set; }
 
  /// <summary>
  /// Дата публикации
  /// </summary>
  [Display(Name = "Дата публикации")]
  [Required(ErrorMessage = "Дата публикации - обязательно поле")]
  [DataType(DataType.Date)]
  public DateTime CreatedAt { get; set; }
 
  /// <summary>
  /// Дата обновления
  /// </summary>
  [Display(Name = "Дата обновления")]
  [DataType(DataType.Date)]
  public DateTime UpdatedAt { get; set; }
 
  /// <summary>
  /// Заголовок
  /// </summary>
  [Display(Name = "Заголовок")]
  [Required(ErrorMessage = "Заголовок - обязательно поле")]
  [StringLength(255, ErrorMessage = "Заголовок не может длиннее 255 символов")]
  public string Title { get; set; }
 
  /// <summary>
  /// Содержание
  /// </summary>
  [Display(Name = "Содержание")]
  [Required(ErrorMessage = "Содержание - обязательно поле")]
  [DataType(DataType.MultilineText)]
  public string Content { get; set; }
 
  /// <summary>
  /// Общее количество просмотров
  /// </summary>
  [Display(Name = "Общее количество просмотров")]
  public int TotalViewCount { get; set; }
 
  /// <summary>
  /// Общее количество просмотров за период
  /// </summary>
  [Display(Name = "Общее количество просмотров за перид")]
  public int PeridViewCount { get; set; }
 
  [ForeignKey("Hall")]
  [Required(ErrorMessage = "Зал - обязательное поле")]
  [Display(Name = "Зал")]
  public int HallId { get; set; }
  public virtual Hall Hall { get; set; }
}

Всё ради данных

Пришло время подключиться к базе данных. Для начала немного поясню. Дело в том, что у меня на этапе разработки будет два подключения к базе данных. То есть в web.config будет указано две строки подключения. Первое будет работать с пользовательской базой, второе - уже непостредственно с классами модели. Возникает вопрос - "Зачем"? Даже с учетом того, что в EntityFramework версии 4.3 появилсь такая замечательная штука как Migrations. Всегда наступает такой момент в процессе разработки, когда базу данных проще удалить, чем писать для нее миграции. Так вот чтобы не удалять при этом пользователей, я буду хранить модели и пользователи в разных базах.

Создадим базу данных с пользователями. Открываем Microsoft SQL Mamagment Studio и создаю новую базу данных. Название ей - museum.

Готово! Теперь надо бы инициализировать таблицы ASP.NET Membership для вновь созданной базы. В наборе сборок NET Framework есть очень много полезных утилит. Одна из них aspnet_regsql.exe. У меня эта утилита лежит в папке:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319/aspnet_regsql.exe

Обратите внимание на то, что папка Framework64 говорит  о 64-разрадной системе, если у вас 32-разрядная версия Windows, то цифр вообще не будет в названии папки с Framework'ом.

Запускаем утилиту. Видим окно, нажимаем далее, попадаем на страницу выбора действия: "Добавляем" или "Удаляем". Нам надо, конечно же, добавить. Нажимаем далее.

Теперь выбирам SQL сервер и название базы данных.

Нажимаем далее и финиш. И перед тем, как начать добавление пользователя, надо указать в файле web.config строку подключения к базе данных. Моя строка подключения выгядит так:

<connectionStrings>
  <add name="ApplicationServices" connectionString="Data Source=(local);Initial Catalog=museum;Integrated Security=True"
     providerName="System.Data.SqlClient" />
</connectionStrings>

 Теперь есть база надо закинуть туда немножко пользователей. Возвращаемся в студию и запускаем конфигуратор сайта (Web Site Administration Tool).

Далее идем в раздел "безопасность" и добавляем одно пользователя. Вы наверное не поверите, но я добавлю себя.

Обратите внимание на то, что на данный момент пользователей 0. Этот факт свидетельствует о том, что поключение к базе указано правильно.

Далее по пунктам:

1. Включаем роли на сайте.

2. Добавляем одну роль "Administrator".

3. Создаем пользователя, не забываем указать галку "Administrator" справа.

4. Смотрим на количество добавленных - правильно, теперь там есть один пользователь с правами администратора.

Итоги этой статьи

У нас практически всё готово, чтобы начать разработку сайта. У нас есть:

  • Шаблон сайта (пусть пока стандартный)
  • База пользователей (пусть пока только один)
  • Подключены роли на сайте (да, опять же только одна)
  • Первичная модель данных (будет много еще разных добавлено позже)
  • Готовы утилиты по распределению скриптов (в том числе и в так называемых UserControl)
  • Обновлены все входящие в проект сторонние фреймворки.

Продолжение в следующей статье, в которой я покажу как подключить Entity Framework (EF) и как начать создавать сайт. Будут созданы первые представления (views) и контроллеры (Controller). Пишите комментарии.

Комментарии к статье (21)

27.04.2012 11:42:12 Nikolay

Отлично, буду читать дальше.

Интересно было бы описать сам паттерн (доходчиво и на примерах кода), плюс нюансы работы с MVC 3 в студии (имя вьюх, моделей, строгая-типизация и прочее).

Спасибо.

 

P.S. "Отпавить на проверку", исправьте ошибку.

27.04.2012 13:18:49 Андрей

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

27.04.2012 13:27:53 Calabonga

Nikolay, о каком паттерне вы говорите? Если про MVC, то мне кажется в интернете, итак, переизбыток информации, и порой даже противоречивой. Со своей стороны могу сказать, что реализация MVC в концепции ASP.NET вся "крутится" вокруг контролера (Controller), то есть, грубо говоря, в ASP.NET паттерн MVC реализован частично.

27.04.2012 13:38:34 Calabonga

Nikolay, о каком паттерне вы говорите? Если про MVC, то мне кажется в интернете, итак, переизбыток информации, и порой даже противоречивой. Со своей стороны могу сказать, что реализация MVC в концепции ASP.NET вся "крутится" вокруг контролера (Controller), то есть, грубо говоря, в ASP.NET паттерн MVC реализован частично.

27.04.2012 13:59:24 готсь

Потемнее бы шрифт, читать тяжело.

02.05.2012 9:36:23 stuhin

>> Особенно, если это разработка коллективная (Team Foundation Server).

>>Поверьте, это реально проще, особенно в начале разработки.

а про drop table слышали? а слышали про внешние ключи на user? и как их делать если базы разные - и как вообще можно умудрится засрать (извиняюсь за выражение - другое здесь не подходит) базу что проще удалить базу чем таблицы? (или данные в таблице удалить - тоже несложно delete from tablename)

03.05.2012 1:17:15 Artyom Krivokrisenko

Я согласен с тем, что разделять данные по 2-м базам - неразумное решение, не имеет нормального обоснования.

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

11.05.2012 13:30:59 Димка

Вот я и дождался этих суперских статей! 

Спасибо!

11.05.2012 13:49:26 Calabonga

Да, уважаемый, Димка! Имеено из-за вас я и решился на этот нелегкий и затратный шаг (по времени затратный). Так что, быстро написать всё сразу не полчится. Да и сайт я реальный переделываю, а там свои заморочки. Вот даже сонники вынес на отдельный сайт, то есть уже целый сайт написал, пока переделывал "музей юмора"... И по ходу придется еще один писать... для значения имен. :)

P.S.: спасибо на добром слове...

13.05.2012 15:05:39 Димка

Имеено из-за вас я и решился на этот нелегкий и затратный шаг (по времени затратный).

---

это же надо))) приятно очень)).

Эх про время вкурсе, два блога веду, не очень благодарное это дело, зато душевное ))))

 

спасибо за ссылку на  сонники, добавил в закладки.

Я вот не могу пока стартануть писать свой сайт из-за того, что мне нужно железо новое купить (материнку, память) и винду переставить, а если переставлять, то сразу ставить восьмерку, я на семерке бете уже года 2 сижу))).   Как думаете все (студия, мс скул) все будет гладко работать?

23.05.2017 9:49:28 Calabonga

У Микрософта всё всегда более или менее начинает работать после первого сервис пака...

 

23.05.2017 9:50:25 Faust

Мне понравилась Ваша статья и вот решил ей воспользоваться в изучении asp.net mvc.

Так вот после

Вместо:

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Должно быть:

@section scripts{
  @Content.Scripts("jquery.validate.min.js", Url)
  @Content.Scripts("jquery.validate.unobtrusive.min.js", Url)
}

После нажатия на Log in(Log on в моем случае), вываливается сообщение

Следующие разделы были определены, но не были обработаны для страницы макета "~/Views/Shared/_LayoutExtended.cshtml": "script".


Не могли бы Вы мне помочь, что я сделал не так?

17.05.2012 0:59:20 Calabonga

Faust, проверьте пожалуйста настройки шаблонов. Скорее всего у вас в файле _ViewStart.cshtml, не установнен стартовый шаблон. У меня он по умолчанию стоит шаблон _LayoutMain.cshtml:

@{
    Layout = "~/Views/Shared/_LayoutMain.cshtml";
}

в котором как раз и присутствует секция scripts: Вот шабон _LayoutMain.cshtml:

@{
  Layout = "~/Views/Shared/_LayoutExtended.cshtml";
}
 
<div id="topmain">
  @RenderSection("header",false)
</div>
 
<div id="main">
  @RenderBody()
</div>
@section scripts{
  @RenderSection("scripts", false)
}
18.05.2012 12:12:32 Димка

все шло нормально, обновил пакеты, установил утилиты дополнительные....

через несколько дней открываю проект а мне ошибка. и в консоле нюгета:

Set-DefaultScaffolder : Object reference not set to an instance of an object.
H:\PROGR\FREE_LANCE\Relax\packages\MvcScaffolding.1.0.6\tools\init.ps1:36 знак:22
+ Set-DefaultScaffolder <<<< -Name Views -Scaffolder MvcScaffolding.Views -SolutionWide -DoNotOverwriteExistingSetting
+ CategoryInfo : NotSpecified: (:) [Set-DefaultScaffolder], NullReferenceException
+ FullyQualifiedErrorId : T4Scaffolding.Cmdlets.SetDefaultScaffolderCmdlet

посмотрел init.ps1:36 знак:22  :

# Ensure you've got some default settings for each of the included scaffolders
Set-DefaultScaffolder -Name Controller -Scaffolder MvcScaffolding.Controller -SolutionWide -DoNotOverwriteExistingSetting

ничего вроде особого...

пробывал переустановить Package MvcScaffolding - безрезультатно...

в итоге проект не открывается.

что это могло так глюкнуть?

18.05.2012 12:13:49 Calabonga

Димка,

честно говоря, даже понятия не имею. Попробую глянуть на выходных, если будет время

18.05.2012 23:25:43 Димка

Попробую глянуть на выходных, если будет время

---

не не нужно, похоже у меня студия гавкнулась 

21.05.2012 19:31:34 Алекс

После обновления всех пакетов, сайт перестал запускаться

21.05.2012 21:13:44 Алекс
Где можно скачать готовый проект?
21.05.2012 23:01:45 Calabonga

Алекс, какая ошибка выдается после обновления?

Проект скачать пока негде...

04.03.2015 0:18:32 Влада

Здравствуйте! у меня возникли проблемы с генерацией _LayoutExtended.cshtml. Использую Visual Studio 2013, перепробовала кучу команд но данный файл не создается. Не подскажете в чем может быть проблема?

04.03.2015 1:20:47 Calabonga

Влада,
К сожалению или к счастью, но ничего ее стоит на месте. Проект, который вы смотрите написан на MVC 3. В новых шаблонах, которые создаются в VS 2013 структура правильная и подмена главного шаблона не требуется. Поэтому он был удалён из списка файлов, которые устанавливаются в пакете MvcTools.

Используйте стандартный файл _Layout.cshtml