Лекции по ASP .NET MVC

Разработка на C# для Gentoo,
 
Посмотрим на лекции по адресу
Урок 0
это просто оглавление
Урок 1
Здесь мы узнаём про то, что в составе Visual Studio есть визарды
но не узнаём что и зачем они делают.
Какой именно код генерируется при каждом из этих двух действий (создание контроллера и создание вида)?
Есть ли аналогичные визарды в составе monodevelop?
Да! нужно встать на диретории View или на её поддиректории и там в контекстном меню будет пункт для генерирования View
(надо бы скриншоты наделать, да описать как это реализовано в коде Monodevelop)
Узнаём, что у NLog есть какая-то консоль
(но почему бы вообще всё про NLog не вывести в отдельный топик?)
Урок 4, routing
Здесь интересно про AreaRegistration (полезно знать, что они вообще есть,и полезно иметь описание сценария (админка и остальной сайт))
Однако описание того, как происходит поиск маршрутов лучше поискать в какой-нибудь другой статье.
Урок 6, авторизация
Тут не используются стандартные классы. Хотя в комментариях подсказывают, что можно было бы.
Урок D. Scaffolding
Что такое scaffolding - непонятно. Похоже, что это генерирование кода C# по спецификации...

Compile time type checking

Есть в VisualStudio, как с этим в mono?

Как создать View

https://www.asp.net/mvc/overview/getting-started/introduction/adding-a-view

Razor-based view templates have a .cshtml file extension
(кем это расширение учитывается? где настраивается?) Например в конфиге Apache прописывается соответствие этого расширения mime-типу?

Метод контроллера возвращает объект типа View.
Нееет, это вызывается метод класса с именем View, который возвращает какой-то объект неясно какого типа (но наследник от ActionResult).
ViewResult derives from ActionResult, instance of the ViewResult class is returned
A common action result is obtained by calling the View method
public ActionResult Index() 
{ 
    return View(); 
}

Почему именно этого типа? Из какого неймспейса этот тип?

uses a view template to generate an HTML response to the browser
public abstract class ActionResult {
	...
	ExecuteResult
	...
}
Почему ActionResult - это абстрактный класс, а не интерфейс?

Как метод View (класса контроллера?) определяет какой .cshtml-файл использовать в качестве шаблона для парсинга и подстановок?
Because you didn't explicitly specify the name of the view template file to use, ASP.NET MVC defaulted to using the Index.cshtml view file in the \Views\HelloWorld folder.
имя файла с шаблоном/текстом - это имя метода контроллера. расширение где-то внутри зашито (как его поменять? например на .csxhtml)
директория Views/HelloWorld - не очень понятно, почему такая (потому что название класса - HelloWorldController)
Где именно внутри View и когда считывается template?
как происходит генерация response?

Чем типизированные View отличаются от нетипизированных?

https://blogs.msdn.microsoft.com/rickandy/2011/01/28/dynamic-v-strongly-typed-views/
There are three ways to pass information from a controller to a view in ASP.NET MVC 3:

  1. As a strongly typed model object.
  2. As a dynamic type (using @model dynamic)
  3. Using the ViewBag

Those are significant advantages and why ASP.NET MVC applications typically use strongly typed views. Strongly-typed view gives you:


чтобы связать представление с передаваемым параметром, надо добавить в представление директиву @model с указанием типа передаваемых данных.
@model middleterraincoatllist.SearchResult
@model IEnumerable<BookStore.Models.Book>
Что значит "связать"?

чтобы не писать полностью имя типа модели, мы можем импортировать пространство имен:
@using BookStore.Models

передавать данные не через объект ViewBag, а напрямую в представление через параметр метода View.

http://metanit.com/sharp/mvc/4.2.php

https://habrahabr.ru/post/116298/
правила, если вы хотите разрабатывать в MVC:

Почему возвращают ActionResult

А, например, не строку (string)
in more complicated action methods, you may need to return different types of results for different scenarios.
какие могут быть (разные?) сценарии?
the registration action method from the default MVC template, redirects the users if registration is successful, but displays the error messages if registration fails.
тут возникает вопрос - а как работает редирект. Он что, возвращает специальный ActionResult?

Какие бывают виды результатов:

The following table shows the built-in action result types and the action helper methods that return them.

Action Result

Helper Method

Description

ViewResult

View

Renders a view as a Web page.

PartialViewResult

PartialView

Renders a partial view, which defines a section of a view that can be rendered inside another view.

RedirectResult

Redirect

Redirects to another action method by using its URL.

RedirectToRouteResult

RedirectToAction or RedirectToRoute

Redirects to another action method.

ContentResult

Content

Returns a user-defined content type.

JsonResult

Json

Returns a serialized JSON object.

JavaScriptResult

JavaScript

Returns a script that can be executed on the client.

HttpStatusCodeResult

(None)

Returns a specific HTTP response code and description.

HttpUnauthorizedResult

(None)

Returns the result of an unauthorized HTTP request.

HttpNotFoundResult

HttpNotFound

Indicates the requested resource was not found.

FileResult

File

Returns binary output to write to the response.

FileContentResult

Controller.File(Byte[], String) or Controller.File(Byte[], String, String)

Sends the contents of a binary file to the response.

FilePathResult

Controller.File(String, String) or Controller.File(String, String, String)

Sends the contents of a file to the response.

FileStreamResult

Controller.File(Stream, String) or Controller.File(Stream, String, String)

Sends binary content to the response through a stream.

EmptyResult

(None)

Represents a return value that is used if the action method must return a null result (void).

Заполнение параметров Action-методов

Когда в Action-метод передаётся объект класса RegisterViewModel model
как этот объект заполняется?

The ASP.NET MVC model binding system automatically maps the named parameters (name and numTimes) from the query string in the address bar to parameters in your method.

Как работает вставка Layout

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
то, что метод контроллера передаёт движку рендеринга, по всей видимости является "моделью" (имеет свойства, к которым можно обращаться).
тут, по всей видимости, используется свойство Layout. Не так ли?
Ниет! ViewResult - Это одно, а объект model, который передаётся внутрь - это другое.

Там - в базовом классе контроллера, ещё есть метод
protected internal virtual ViewResult View(
	string viewName,
	string masterName,
	object model
)
Как masterName используется? Куда попадает?

@{
    ViewBag.Title = "Index";
}
откуда тут слово ViewBag, что имеется в виду?
ViewBag object contains data that will be passed to the view automatically.

~/Views/Shared/_Layout.cshtml
@RenderBody() line. RenderBody is a placeholder where all the view-specific pages you create show up, "wrapped" in the layout page.

Layout (мастер страницы) – это тоже View и они тоже хотят свои модели.
Cоздайте в приложении класс SharedLayoutViewModel с нужными вашему _Layout.cshtml свойствами, и наследуйте от него ваши модели для остальных View.
Пользуйтесь Result-фильтрами чтобы наполнять эту модель в одном месте для всех методов ваших контроллеров.
Или переопределите OnResultExecuting в базовом классе ваших контроллеров, и делайте это там.

Синтаксис Razor

Razor minimizes the number of characters and keystrokes required when writing a view template
минимизирует по сравнению с чем, с каким другим синтаксисом?
Надо ли это включать в начало курса обучения, или обсуждение этого вопроса можно отложить на внеклассные занятия?

Модели

считайте ViewModel — это как контракт между контроллером и View.
ViewModel — это самый что ни на есть строгий контракт между контроллером и View, совершенно предсказуемый и тестируемый.

Вполне жизнеспособным выглядит вариант такой структуры:
677695b4.png
это отличается от варианта генерируемого monodevelop, в котором ViewModels называются просто Models и нет поддиреторий для каждого View

все модели находятся в одном пространстве имён (NameSpaceProvider=False для их директорий)
Можно убрать ViewModel и оставить Model (но ViewModel явно говорит, что эта модель именно для View, а где-то могут быть другие модели)

создание Html.InputFor(m=>m.Field), где сам label, разные звёздочки (обязательное поле) и инпут строится целиком по метаданным модели — это вполне практичный подход.
формы желательно стандартизировать, и создавать EditorTemplates, а для особых исключений, в виде аннотаций к ViewModel подписывать нужные UIHint-ы,
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/04/24/how-we-do-mvc.aspx

Домен (Domain model)

Вы должно быть подумали, что я предлагаю добавлять в домен такие вещи как, например, IsUserLocationVisible, которые служат исключительно для того, чтобы определить показывать местоположение юзера на сайте или нет. Если добавить это поле в домен, то конечно же домен начинает зависить от View. И это будет костылем. Вы бы, я так полагаю, добавили это поле во ViewModel.

Я же предлагаю следующее, формализовать то бизнес-правило, на основании которого определяется показывать юзера на сайте или нет и внести его в домен. Допустим нам нужно показывать местоположение юзера, только если он дружелюбный, тогда в домене это будет поле IsFriendly с некой логикой внутри. Которое никаким образом не связано с UI. И на основании уже этого поля определять во View показывать его или нет.

В итоге, я хочу сказать, что вместо того чтобы добавлять поле IsUserLocationVisible во ViewModel лучше добавить в домен IsFriendly.

Атрибуты

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
зачем нужен и как применяется каждый из них?

Как работает редирект

return RedirectToAction("Index", "Home");

Как накапливаются сообщения об ошибках

AddErrors(result);

Своевременно ли вообще изучение MVC

Или учить его в 2017 это всё равно, что учить MFC ?
2012-06-17, https://weblogs.asp.net/sbwalker/microsoft-declares-the-future-of-asp-net-is-web-api
Windows-Live-Writer-3bbb05c21d6d_97B7-WebAPI_thumb.png
WebApi is focused on full implementation of HTTP spec
Web API is designed to embrace native HTTP standards without copious layers of abstraction, the “Future of ASP.NET” (3-4 years into the future, all ASP.NET web applications will be developed using the Web API approach. i.e. 2015+)
designed to be the ultimate replacement for both the REST aspects of WCF and ASP.NET MVC Web Services.
Web API promotes client-side page compositing with a heavy focus on web services (whereas, MVC is a server-side page compositing framework)
web API is simply a rest-ful URL (i.e.: mysite.com/api/products) that can be accessed through a variety of methods (GET,POST,PUT,DELETE) and return a variety of responses.
The responses are typically JSON, XML, or some other type of data format which can be read programmatically (i.e.: not by humans).
http://www.sql.ru/forum/989503-1/mvc-myortv-da-zdravstvuet-webforms

Литература

хороша книжка Стивена Сандерсона “Pro ASP.NET MVC 2 Framework”. Благодаря ей удалось избежать многих ошибок

IsAuthenticated

как бороться с использованием IsAuthenticated во вьюшках, кроме банального пробрасывания этого поля и такого же использования как и то, с чем боремся.

в таких случаях пользуюсь RenderAction — в соответствующем контроллере есть логика, которая проверяет IsAuth (значение берется из входного параметра с использованием соответствующего Binder-а), а затем контроллер выдает один из двух контролов. И ничего, что они простые, зато следуют SRP (single responsibility principle). Простота во вью еще важнее, чем в исполняемом коде.

с точки зрения View, там где вы используете IsAuthtenticated, скорее всего должно быть свойства вроде [bool]Model.ShowUserControls и другие

Однажды, вы захотите использовать этот же шаблон к примеру генерирующий ту же страницу в режиме для администратора: View this page from USER1 perspective.

Это только 1 конкретный пример почему данные должны быть явными, а шаблоны глупыми.

Именно контроллер должен позаботиться о том, чтобы View была предоставленна необходимая (не больше) для него модель собранная из данных, контекста и т.п.

пример — надо показать залогиненому пользователю один текст, незалогиненому другой. Верстка — разная ( т.е. передать текст из контроллера не получится, передавать с версткой — глупости). Пилить 2 контрола на каждую простую вьюшку — ну тоже странновато. Максимум что стоит делать для изолированности — пробрасывать значение через модель.

View не должно зависеть от Request, как кстати, и контроллер.

Вы можете включить свойство IsUserAuthenticated в исходящую View-модель (для этого зачастую приходится создавать layer-supertype, то есть базовую ViewModelBase), или же использовать для этого ViewBag (который весьма разумно использовать для таких «побочных» вещей, но не рекомендуется для передачи основных данных — для этого есть View-модель).

Валидация

рано или поздно правила валидации выходят за рамки сущностей модели, иногда противоречит им, и вы начинаете размазывать валидацию по проекту, часто дублировать её, делать исключения то там то там.

вы проверяете _форму_, а не объект, поэтому валидация формы — это проверка состояния формы, а не связанных сущностей, как вырожденный случай.

самый удачный пример реализации валидации — на мой взгляд реализовано в Python FormEncode. валидатор — это объект со своей гибкой структурой, произвольной вложенность, и заодно ModelBinder (в понятиях MVC)
Насчет гибкости валидатора — в .NET есть тот же FluentValidation (прекрасная вещь), но DefaultModelBinder «из коробки» юзает DataAnnotations.

Насчет ASP.NET MVC — мне очень НЕ нравится, что там на архитектурном уровне смешали валидацию и Model-binding, и то, что DefaultModelBinder всегда проводит валидацию, даже когда это не нужно. Но это пол-беды — ведь есть еще domain-level-валидация (построенная, например, на FluentValidation), и приходится серьезно поднапрячься, чтобы поддерживать ModelState в нормальном состоянии (чтобы не выводить лишних ошибок, и чтобы при этом были выведены все ошибки формы за раз).
На мой взгляд, это можно было сделать порядком проще, и чтобы не пришлось заморачиваться с ModelValidatorProvider'ами. Нужно было сделать DataAnnotations менее навязчивыми, что ли.

AutoMapper

Самая засада — mapping из доменной модели во ViewModel, и обратно. Но и эта проблема решается с помощью AutoMapper'а.
http://automapper.codeplex.com/

EmitMapper, который в несколько раз быстрее

ViewBag

https://weblogs.asp.net/scottgu/announcing-asp-net-mvc-3-release-candidate-2
ViewBag is new to MVC 3 and has the advantage that it can be used in combination with a strongly typed model, giving you the advantages for both.

dynamic — это loose-контракт, и никак не альтернатива и не «хотя бы» по сравнению со строгой типизацией. Но использовать можно, просто для особых сценариев.
Я одно время сам был сторонником исключительно строгих контрактов. Однако, в контексте того же ASP.NET MVC оказалось очень предпочтительно использовать ViewBag для передачи дополнительных данных во View (что-то вроде AOP). С одной стороны — loose-contract, а с другой — он не имеет отношения к основному View, не засоряет его ViewModel, и не мешает всей strong-type-овости всех основных View.
Для основных View, все же, на практике оказалась более предпочтительной модель со строгой типизацией View. Количество ViewModel-ей перестает волновать, когда они созданы по определенному соглашению, лежат в нужном месте и хорошо структурированы.

когда даже над одной страницей работают больше 2х человек ( даже 2 — уже неудобно) — нестрогая типизация ViewModel приводит к головной боли — лазить и смотреть как же твой коллега назвал то, куда он данные Х сложил. А еще есть опечатки при верстке (верстальщик же не должен быть программистом, он сделал все правильно, это у вас не работает ) и рефакторинг такого — тот еще ад.
dynamic - ExpandoObject
Никак не проверяется. С dynamic-типами работает DLR (используя позднее связывание). все проверяется в runtime (связывание происходит совершенно точно в DLR, с использованием DynamicMetaObject).

Разные формы регистрации

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

А как же локализация и ресурсы?

Структура проекта

как уважаемая компания относится к тому, чтобы папки организовывать не по принципу разделения классов на роли (контроллеры сюда, модели туда), а по фичам?
для этого в Orchard CMS есть отдельные .dll-ки (модули)

Scaffolding (заготовки)

http://andrey.moveax.ru/post/mvc3-in-depth-basics-06-scaffolding
https://www.codeproject.com/Articles/1011748/Scaffolding-in-ASP-NET-MVC
http://www.dotnettricks.com/learn/mvc/understanding-aspnet-mvc-scaffolding
Scaffolding engine for ASP.NET MVC models helps web developers in relieving him from the tedious & mundane task of writing CRUD Operations codes. That is, connecting to a database table and perform often doing task such as Create, Retrieve, Update and Delete records.
Scaffolding engine uses Microsoft’s T4 templates to generate basic controllers and views for the models. Scaffolding blends with Entity framework and creates us the instance for the mapped entity model and writes down CRUD Operations code for us. That’s really charming and time saving that enhances developer’s productivity.