Pull to refresh

Быстрое создание прототипа веб приложения в ASP.NET MVC 3 с использованием MvcScaffolding

ASP *
Sandbox
В этой статье я бы хотел рассмотреть возможность быстрого создания функционального прототипа веб приложения на основе технологии ASP.NET MVC 3. Немного соприкоснувшись с «Ruby on Rails», я заинтересовался его возможностью Scaffolding-га т.е. быстрого способа генерации основного каркаса приложения. Это дает возможность разработчику сконцентрироваться на создании бизнес модели и получить функциональный прототип не тратя свое время на детали реализации, что очень важно в начале любого проекта. А существует что-либо подобное в ASP.NET MVC? И насколько это функционально, быстро, удобно и практично.
Я хотел бы рассмотреть это на конкретном примере, и в этом качестве предлагаю создать простой веб каталог товаров. В моем случае это будет каталог автозапчастей.
В качестве инструментов, я буду использовать следующие средства разработки и библиотеки.
  • MS Visual Studio 2010
  • ASP.NET MVC 3 – официальный релиз
  • NuGet – менеджер пакетов для Visual Studio
  • MvcScaffolding — генератор кода MVC на основе шаблонов
  • EFCodeFirst — новая возможность Entity Framework CPT5



Установка и настройка


Прежде всего, необходимо настроить наше окружение. Найдите в менеджере расширений Visual Studio расширение NuGet и установите его. Либо скачайте и установите с официального сайта.
Создайте новый ASP.NET MVC 3 проект.
Далее нужно с помощью командной стоки менеджера пакетов установить MvcScaffolding. Откройте консоль NuGet: Главное меню «View” → „Other Windows“ → „Package Manager Console“.
Как мы увидим позже, эта командная строка является основным средством работы с MvcScaffolding, и аналогична командной стоке в Rails.
Для установки пакета достаточно выполнить команду:

Install-Package MvcScaffolding


image

Как можно видеть, эта команда установит пакет MvcScaffolding в ваш проект, а также пакет EFCodeFirst, который находится в зависимости(в моем случае я установил EFCodeFirst раньше).

Модель данных и предметная область приложения


Приложение, которое я собираюсь разработать в этом примере, является простым каталогом автозапчастей и может являться частью магазина или учетной системы.
Для начала, нам нужно смоделировать предметную область.
Итак, что у нас есть:
  • Марка машины
  • Модель
  • Год выпуска
  • Запасная часть

Создадим основные классы бизнес сущностей.

public class Make
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Model> Models { get; set; }
  }

public class Model
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public int MakeId { get; set; }
    [NotMapped]
    public string FullName
    {
      get { return string.Format("{0} {1}", Make.Name, Name); }
    }
    virtual public Make Make { get; set; }
    public List<Release> Years { get; set; }
  }

public class Release
  {
    public int Id { get; set; }
    public int ModelId { get; set; }
    public int YearId { get; set; }
    [NotMapped]
    public string FullName
    {
      get { return string.Format("{0} ({1})", Model.FullName, Year.Value); }
    }
    virtual public Model Model { get; set; }
    virtual public Year Year { get; set; }
    public List<Part> Parts { get; set; }
  }

public class Part
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public int GroupId { get; set; }
    virtual public Group Group { get; set; }
    public List<Release> Releases { get; set; }
  }


* This source code was highlighted with Source Code Highlighter.

Как можно видеть, у нас есть отношение „один-ко-многим“ между „Моделью“, „Маркой“ и „Выпуском“ а так же отношение „многие-ко-многим“ между „Запчастями“ и „Выпуском“. Мне было интересно как MvcScaffolding отработает эти отношение и какой код будет создан в результате. Забегая вперед, нужно отметить следующие правила, которые нужно соблюдать при описании классов бизнес модели:
  • Указывать первичный ключ. Это может быть Id, {ИмяСущьности}Id либо атрибут [Key]
  • Указать внешний ключ {ИмяСущьности}Id
  • Нет поддержки комплексных первичных ключей. Но может это и к лучшему, потому как с ними много других проблем.

В нашем случае в „Model“ мы включили поле MakeId – внешний ключ от „Mark“, а так же виртуальное поле Make. Это реализует отношение „один-ко-многим“. Для реализации отношения „многие-ко-многим“ мы добавили соответствующие свойства-списки в классы „Part“ и „Release“
Для парадигмы CodeFirst этого описания классов достаточно: нам нет нужды заботится о хранении и генерации, все будет делаться автоматически, при старте приложения. После окончания работы с моделью необходимо обязательно собрать проект.

Настройка шаблона и создание контроллеров


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

Scaffold CustomTemplate MvcScaffolding.RazorView _CreateOrEdit
Scaffold CustomTemplate MvcScaffolding.RazorView Edit
Scaffold CustomTemplate MvcScaffolding.RazorView Index
Scaffold CustomTemplate MvcScaffolding.Controller ControllerWithRepository

В результате в нашем проекте появиться новая папки с шаблонами.

image

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

Scaffold Controller Make -Verbose -ControllerName Make -DbContextType ApartsContext -Repository

Тут:
  • Scaffold Controller — команда создания контроллера
  • Make – имя класс модели
  • -ControllerName Make— указываем имя контроллера, не обязательно, но по умолчанию генериться множественная форма от имени модели
  • -DbContextType ApartsContext — класс контекста
  • -Repository — указывает, что необходимо использовать доступ к данным через репозиторий

В результате у нас создаются следующие файлы и классы
  • Контроллер MakeController, который содержит методы создания, удаления, изменения и отображения в виде списка для сущьности Make
  • Контекст ApartsContext (если он не был создан), который обеспечивает связь с хранилищем
  • Репозиторий MakeRepository — реализация основных базнес правил
  • Файлы представлений _CreateOrEdit.cshtml, Create.cshtml Delete.cshtml Details.cshtml Edit.cshtml Index.cshtml

Я не буду тут приводить генерируемый код, тем кому интересно могут скачать исходники проекта по ссылке в конце статьи.
Теперь давайте аналогично создадим второй контроллер:

Scaffold Controller Model -Verbose -ControllerName Model -DbContextType ApartsContext -Repository

Откроем созданное представление _CreateOrEdit.cshtml и посмотрим на сгенерированный код:
...
@Html.DropDownListFor(model => model.MakeId, ((IEnumerable<ApartCatalogMvc.Models.Make>)ViewBag.PossibleMakes).Select(option => new SelectListItem {
    Text = (option == null ? "None" : option.Name),
    Value = option.Id.ToString(),
    Selected = (Model != null) && (option.Id == Model.MakeId)
  }), "Choose...")
...


* This source code was highlighted with Source Code Highlighter.

А так же в коде контроллера:
...
public ActionResult Edit(int id)
{
  ViewBag.PossibleMakes = makeRepository.GetAllMakes();
...


* This source code was highlighted with Source Code Highlighter.

С ситуацией отношения „один-ко-многим“ MvcScaffolding справился очень хорошо: в представлении редактирования „Model“ был создан выпадающий список, который заполняется значениями из „Mark“.
Продолжим создавать наши контроллеры:

Scaffold Controller Release -Verbose -ControllerName Releases -DbContextType ApartsContext -Repository
Scaffold Controller Part -Verbose -ControllerName Part -DbContextType ApartsContext -Repository

Соответствующие контроллеры, представления и репозитории были созданы. Тут также с отношением „один-ко-многим“ практически все хорошо(можно лишь заменить свойство Name на FullName в параметрах создания выпадающего списка для лучшего отображения), однако, для отношения „многие-ко-многим“ MvcScaffolding ничего не создал, так, что нам нужно либо добавлять это вручную или изменять шаблон генерации (эта отдельная тема, я постараюсь написать и дать пример реализации в другой статье и сообщить автору MvcScaffolding, возможно он включит это в следующий релиз).
Теперь нам осталось только создать репозитории для справочников и других классов, у которых нет контроллеров.

Scaffold Repository Year -DbContextType ApartsContext -Verbose
Scaffold Repository Group -DbContextType ApartsContext -Verbose

Настало время первого запуска.
Перед этим, необходимо записать в конфигурацию строку подключения к базе данных. Если это SQL Express, то допускается отсутствие физического файла.
<add name="ApartsContext"
     connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\ApartsDB.mdf;Integrated Security=True;User Instance=True;Initial Catalog=ApartsDB"
     providerName="System.Data.SqlClient"/>


* This source code was highlighted with Source Code Highlighter.

Важно, что бы имя строки подключения совпадало с именем класса контекста.
Кроме этого, я бы хотел иметь тестовые данные и заполненные справочники. Для этого добавим класс, унаследованный от класса DropCreateDatabaseAlways, который будет каждый раз инициализировать нашу базу данных.
public class ApartsInitializer : DropCreateDatabaseAlways<ApartsContext>
  {
    protected override void Seed(ApartsContext context)
    {
      var makes = new List<Make>
      {
        new Make { Name = "BMW"},
        new Make { Name = "Mazda" }
      };
      makes.ForEach(m => context.Makes.Add(m));
...

* This source code was highlighted with Source Code Highlighter.

А в Global.asax при старте приложения добавим:
...
DbDatabase.SetInitializer<ApartsContext>(new ApartsInitializer());
...


* This source code was highlighted with Source Code Highlighter.

Подправив немного полученный код, мы получили функционально рабочее приложение.

image

Заключение


В результате на создание функционального прототипа я потратил всего пару часов, со всеми доработками.
Возможности, которых мне явно не хватало при работе:
  • Пейджинг и фильтрация в списках
  • Поддержка отношений „многие-ко-многим“
  • Биндинг для различных типов данных, например для DataTme

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

Дополнительные материалы


Блог автора MvcScaffolding
Исходный код примера
Tags:
Hubs:
Total votes 51: ↑39 and ↓12 +27
Views 6.6K
Comments Comments 16