Про розробку по і ефективності 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 Tools Update - новий шаблон "Intranet Application" і підтримку семантичної розмітки HTML5. Unit-тести поки залишу за кадром, щоб не роздувати розмір статті.
Тепер, після створення проекту, студія зустрічає нас відкритим файлом readme.txt (з описом налаштування в різних IIS). До речі, того хто це придумав - від мене п'ять з плюсом :) Правда зараз нам це не особливо цікаво.
Далі ми бачимо, що в звичній структурі проекту відсутня AccountController і всі пов'язані з ним файли - це наслідок вибору шаблону для Intranet.
Тепер, давайте створимо прості моделі, відповідно до постановкою завдання вище. До речі, для спрощення їх створення я зробив у себе в Resharper шаблон файлу SimpleModel для того, щоб не створювати кожен раз властивості "Id" і "Name". Це теж, до певної міри, scaffolding, однак я не буду зараз розповідати про Resharper взагалі і його шаблони зокрема, хоча і дуже хочеться :)
Після застосування шаблону клас моделі виглядає так:
Зараз вже можна додавати контролери з контекстного меню в Solution Explorer:

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

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


Як бачите, працює і валідація, хоча для роботи ненав'язливою валідації на введення дробових чисел і дат в українській форматі доведеться здійснювати додаткові рухи тіла.
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 і буде тепер використовуватися для генерації (при цьому повернутися до використання стандартного можна просто видаливши цей шаблон або перейменувавши його):

Тепер просто додаємо необхідну пару рядків в цей файл, зберігаємо його, і запускаємо команду:
PM> Scaffold Controller Manufacturer -Repository -Force
Останній параметр говорить про те, що ми ходимо перезаписати наші існуючі файли.
Якщо ми перезапустити програму, то побачимо, що ненав'язлива валідація заробила.
Моя думка, в результаті, що обидва варіанти scaffolding це хороші інструменти для свого кола завдань. Вельми порадувала можливість розширення. А про те, як їй можна скористатися для написання власних генераторів, я розповім наступного разу.
Всегда пожалуйста :) Відповідаю.
1. Чи буде, ймовірно не одна. Точної дати поки назвати не можу.
2. Якщо коротко - добре тим, що не дублюємо, погано тим, що іноді потрібно робити створення і редагування трохи по-різному, а такий підхід трохи зупиняє від того, щоб взяти і розділити на два view (адже вже працює :)