
В интернете полно примеров вроде «Делаем вики на ASP.NET MVC за 15 минут». Проблема таких примеров в том, что они используют VideData или ViewBag для передачи данных в View. Для генерации форм используются нетипизированные методы вроде
Html.TextBox()
. А для получения данных из форм просто параметры к методам контроллера, или хуже того – сами сущности из ORM.Это может быть прекрасно с точки зрения того, кто в жизни имеет дело только с созданием таких «видео уроков». Но в немного более сложных случаях вы, конечно же, захотите иметь строго типизированные модели, использовать строго типизированные методы вроде
Html.TextBoxFor(m=>..)
, и получать в методе контроллера из формы ровно то, что хотите получить и при этом держать все модели в консистентном виде. Итак, правила, если вы хотите разрабатывать в MVC:
- Каждому View свой персональный класс ViewModel.
- Только View диктует, какие будут свойства у ViewModel. Остальное – проблемы контроллера.
- ViewModel – это простой DTO, без логики.
- View использует только те данные, которые приходят из ViewModel, ничего больше. Не трогайте
Request.IsAuthenticated
в ваших View, для этого есть модель.
Может возникнуть вопрос, а как быть с _Layout (мастер страницами) – ведь это тоже View и они тоже хотят свои модели. Вполне резонно – ведь мы помним, что view диктует модель, всё остальное следует потом. Поэтому создайте в приложении класс SharedLayoutViewModel с нужными вашему _Layout.cshtml свойствами, и наследуйте от него ваши модели для остальных View. Пользуйтесь Result-фильтрами чтобы наполнять эту модель в одном месте для всех методов ваших контроллеров. Или переопределите
OnResultExecuting
в базовом классе ваших контроллеров, и делайте это там.Для удобства организуйте ваши модели в директории. Вполне жизнеспособным выглядит вариант такой структуры:

Обрабатываем формы
Попробуем создать контроллер, модель и view для такой формы:

Для этого мы добавим View, в качестве модели которого укажем
AccountRegisterViewModel
:@model AccountRegisterViewModel
<h2>
Register</h2>
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<label>
Name
@Html.TextBoxFor(m => m.Form.Name)
</label>
<label>
State
@Html.DropDownListFor(m => m.Form.State, Model.StateSelectList)
</label>
<input type="submit" value="Register me" />
}
Добавим в проект в директорию ViewModels/Account класс модели, который включает в себя данные для выпадающего списка State и свойство с самой формой (здесь одна, а в жизни их может быть несколько в одном View):
public class AccountRegisterViewModel : SharedLayoutViewModel<br/>
{<br/>
public AccountRegisterForm Form { get; set; }<br/>
<br/>
public IEnumerable<SelectListItem> StateSelectList { get; set; }<br/>
}
Для нашей формы мы определим отдельный класс. Он будет включать себя нужные атрибуты DataAnnotations для валидации формы, и может быть, даже когда-нибудь реализует IValidatableObject:
public class AccountRegisterForm<br/>
{<br/>
[Required]<br/>
public string Name { get; set; }<br/>
<br/>
[Required]<br/>
public string State { get; set; }<br/>
}
Сам контроллер тога будет выглядеть так:
[HttpGet]<br/>
public ActionResult Register()<br/>
{<br/>
var model = new AccountRegisterViewModel();<br/>
<br/>
SetupRegisterViewModel(model);<br/>
return View(model);<br/>
}<br/>
<br/>
[HttpPost]<br/>
public ActionResult Register([Bind(Include = "Form")]AccountRegisterViewModel model)<br/>
{<br/>
if (ModelState.IsValid)<br/>
{<br/>
// save model.Form <br/>
<br/>
TempData["Message"] = "Thank you for registering";<br/>
return RedirectToAction("Index");<br/>
}<br/>
<br/>
SetupRegisterViewModel(model);<br/>
return View(model);<br/>
}<br/>
<br/>
private void SetupRegisterViewModel(AccountRegisterViewModel model)<br/>
{<br/>
model.StateSelectList = new SelectList(new[] { string.Empty, "NY", "VA" });<br/>
}
Вот и всё.
Надеюсь, этот пример станет полезным разработчикам ASP.NET MVC, особенно тем, кто создаёт на нём приложения, а не видео уроки.
P.S. Отмечу, что выбранный пример для этого подхода не показательный. Форма из двух полей без форматирования выбрана только ради экономии времени читателя.