Про розробку по і ефективності mvc 3 scaffolding

Оскільки в минулій статті я вже розповів про основні поняття і бібліотеки (ASP.NET MVC, Entity Framework), зараз я не буду на них детально зупинятися. Приклад буде використовувати scaffolding. який я вже згадував в попередній раз.

Disclaimer. Зазначу, що scaffolding - це, взагалі кажучи, швидка генерація чого-небудь, з метою подальшого доопрацювання, а не спосіб швидко написати закінчене складне додаток.

Мабуть, єдине, на чому я забув зупинитися в минулий раз, це NuGet. Сама ідея його не нова (apt-get, Ruby Gems і т.п.), однак те, що це тепер доступно і в Visual Studio дуже радує. Слідуючи опису з офіційного сайту:

NuGet is a Visual Studio extension that makes it easy to install and update open source libraries and tools in Visual Studio.

В принципі, додати нічого, проте я все-таки трохи додам :)

Також важливо відзначити, що при створенні свого пакета можна вказати залежності, які завантажуються і встановляться автоматично. Ймовірно, для кого-то буде також цікава можливість підключення приватного джерела пакетів (простенький сервер або загальна папка) нарівні з nuget.org.

Більш докладно про NuGet і Package Manager можна прочитати в документації на офіційному сайті. А тим, хто вважає за краще формат блогу можу порекомендувати статтю Scott Hanselmann - Introducing NuPack Package Management for .NET - Another piece of the Web Stack.

Налаштування з'єднання з базою даних

Для того, щоб не прив'язуватися до встановлених (або невстановлених) версіями, я вирішив використовувати Microsoft SQL Server Compact Edition - це легка СУБД, для якої не потрібно налаштування і не потрібно запускати сервіси.

Щоб використовувати SQL Server CE досить завантажити відповідний пакет (якщо SQL Server CE ще не підключений до проекту), виконавши в консолі команду:

PM> Install-Package SqlServerCompact

Після цього потрібно поправити в web.config існуючий рядок з'єднання (за замовчуванням використовується ApplicationServices) і додати рядок з'єднання з назвою, що збігається з назвою контексту (щоб додатково нічого не налаштовувати):

Для довідки - до релізу Entity Framework 4.1 (де з'явилася його підтримка в CodeFirst) можна було скачати NuGet-пакет EFCodeFirst.SqlServerCompact, який (разом кількома іншими пакетами) додавав таку підтримку до Entity Framework 4.

Налаштування генерації бази даних

Припустимо, ми плануємо в подальшому розвивати нашу модель, а це зазвичай і трапляється з реальними проектами, чи не так? ;) У цьому випадку нам знадобиться пересоздавать базу даних, якщо змінилася модель (якщо залишити все за умовчанням, то в цьому випадку отримаємо exception). Для цього достатньо в "Global.asax.cs" дописати один рядок в методі "Application_Start":

Про всяк випадок уточню кілька моментів:

  • Не використовуйте цей режим у дослідній / промислової експлуатації, тому що ви втратите дані, введені користувачами.
  • Для заповнення бази тестовими даними можна успадкувати свій клас від DropCreateDatabaseIfModelChanges і перевизначити метод Seed. Детальніше про це можна прочитати в блозі команди ADO.NET.
  • Використовується простір імен "System.Data.Entity" (це якщо раптом ваша IDE не дозволяє автоматично пропонувати додати using).

Постановка задачі

Давайте поставимо завдання так:

По суті, ми зараз описали набір моделей для нашого застосування. Самі моделі ми створимо трохи пізніше. Що стосується створення моделей, то по-правильному їх потрібно створювати в окремому проекті типу "Class Library", проте, сподіваюся, ви мені вибачте їх створення в тому ж проекті :)

Зверніть увагу: постановка завдання дуже проста, зокрема, немає зв'язків багато-до-багатьох, без яких рідко обходяться реальні програми. Тому, щоб не бути звинуваченим в підтасовуванні фактів;), хочу зазначити - на даний момент офіційного варіанта scaffolding'а зв'язків багато-до-багатьох немає, проте, при бажанні, можна написати свій Scaffolder (термін з MvcScaffolding, про це пізніше). Те ж ймовірно відноситься і до інших місій, які я не охопив своїм прикладом.

Scaffolding: стандартний спосіб

Для того, щоб генерувати контролери та подання стандартним способом, нам буде потрібно встановити MVC 3 Tools Update. Про всяк випадок нагадаю, що це оновлення не стосується бібліотеки, а містить тільки оновлені інструменти, в тому числі для створення контролерів і уявлень.

Створимо новий проект, вибравши зі списку "ASP.NET MVC 3 Web Application". В процесі нам запропонують уточнити параметри проекту:

Про розробку по і ефективності mvc 3 scaffolding

Заодно хочу звернути увагу на нововведення в MVC 3 Tools Update - новий шаблон "Intranet Application" і підтримку семантичної розмітки HTML5. Unit-тести поки залишу за кадром, щоб не роздувати розмір статті.

Тепер, після створення проекту, студія зустрічає нас відкритим файлом readme.txt (з описом налаштування в різних IIS). До речі, того хто це придумав - від мене п'ять з плюсом :) Правда зараз нам це не особливо цікаво.

Далі ми бачимо, що в звичній структурі проекту відсутня AccountController і всі пов'язані з ним файли - це наслідок вибору шаблону для Intranet.

Тепер, давайте створимо прості моделі, відповідно до постановкою завдання вище. До речі, для спрощення їх створення я зробив у себе в Resharper шаблон файлу SimpleModel для того, щоб не створювати кожен раз властивості "Id" і "Name". Це теж, до певної міри, scaffolding, однак я не буду зараз розповідати про Resharper взагалі і його шаблони зокрема, хоча і дуже хочеться :)

Після застосування шаблону клас моделі виглядає так:

Зараз вже можна додавати контролери з контекстного меню в Solution Explorer:

Про розробку по і ефективності mvc 3 scaffolding

У діалозі вибираємо назву контролера, клас моделі і контекст (якщо немає, створюємо новий):

Про розробку по і ефективності mvc 3 scaffolding

Шляхом нескладного експерименту було з'ясовано, що для вказівки контексту в окремій папці (наприклад, Models), необхідно вказувати цю папку через точку - "Models.MvcDemoContext".

Тепер, після натискання на кнопку "Add" ми можемо спостерігати невелике диво (принаймні для тих, хто жодного разу не бачив scaffolding в дії) - до нашого проекту додаються необхідні файли і, після запуску програми, ми можемо виконувати всі операції набору CRUD (Create / Read / Update / Delete) над нашими моделями. Більш того, за замовчуванням працює ненав'язлива валідація.

Про розробку по і ефективності mvc 3 scaffolding

Про розробку по і ефективності mvc 3 scaffolding

Як бачите, працює і валідація, хоча для роботи ненав'язливою валідації на введення дробових чисел і дат в українській форматі доведеться здійснювати додаткові рухи тіла.

MvcScaffolding - основи

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

Виконуємо в консолі команду:

PM> Install-Package MvcScaffolding

Ця команда встановить заодно і T4Scaffolding (пакет, що містить інфраструктуру для scaffolding взагалі).

PM> Scaffold Controller Manufacturer -Repository

Ця команда створить контроллер і уявлення, що підтримують CRUD-операції. При цьому є два серйозних відмінності від нашого попереднього варіанту (крім косметичних).

Для повторного використання розмітки по створенню і редагуванню використовується partial view "_CreateOrEdit.cshtml". Зараз я не буду зараз зупинятися на перевагах і недоліках такого підходу. Скажу тільки, що, по-перше, ніхто не заважає потім відредагувати уявлення, а, по-друге, можна переробити шаблони для генерації і навіть сам генератор (про це докладніше розповім далі).

За допомогою параметра "Repository" ми додатково згенерували інтерфейс "IManufacturerRepository" і клас "ManufacturerRepository". Щоб не описувати їх детально, просто приведу опис інтерфейсу:

Завдяки цьому, ми тепер можемо досить просто використовувати Interface Injection. скажімо, для модульного тестування.

MvcScaffolding - настройка

Якщо ви сгенеріруете уявлення за допомогою MvcScaffolding, то ви виявите, що ненав'язлива валідація для них не працює. Причина в тому, що, на відміну від стандартного scaffolding (в MVC 3 Tools Update), в уявленнях відсутні такі рядки підключення скриптів:

Як варіант, можна їх додати в "_Layout.cshtml" (у чому, знову ж таки, є свої плюси і мінуси), проте давайте відтворимо поведінку стандартного scaffolding.

Для цього запустимо в консолі команду:

PM> Scaffold CustomTemplate MvcScaffolding.RazorView Create

Після виконання цієї команди в нашому проекті з'явиться файл "Create.cs.t4", який є шаблоном T4 і буде тепер використовуватися для генерації (при цьому повернутися до використання стандартного можна просто видаливши цей шаблон або перейменувавши його):

Про розробку по і ефективності mvc 3 scaffolding

Тепер просто додаємо необхідну пару рядків в цей файл, зберігаємо його, і запускаємо команду:

PM> Scaffold Controller Manufacturer -Repository -Force

Останній параметр говорить про те, що ми ходимо перезаписати наші існуючі файли.

Якщо ми перезапустити програму, то побачимо, що ненав'язлива валідація заробила.

Моя думка, в результаті, що обидва варіанти scaffolding це хороші інструменти для свого кола завдань. Вельми порадувала можливість розширення. А про те, як їй можна скористатися для написання власних генераторів, я розповім наступного разу.

Всегда пожалуйста :) Відповідаю.

1. Чи буде, ймовірно не одна. Точної дати поки назвати не можу.
2. Якщо коротко - добре тим, що не дублюємо, погано тим, що іноді потрібно робити створення і редагування трохи по-різному, а такий підхід трохи зупиняє від того, щоб взяти і розділити на два view (адже вже працює :)