Razor Pages — новая фича, появившаяся в Core.Net 2.0. Razor Page — это страница, состоящая из стандартной разметки (View) и бэкенд класса. В каком то смысле напоминает Web Forms только без поддержки сохранения состояния. Преимущество такого решения очевидно — мы избавляемся от ненужной прослойки — модели страницы (модель данных в виде например Entity это само собой). Бэкенд страницы является и контроллером и моделью — классика ООП — инкапсуляция данных и методов работы с ними в одном объекте. В конце концов модель страницы — это просто класс, нет никаких причин почему этим классом не может быть контроллер.
Иными словами, Razor Pages — более вменяемое решение для веба чем MVC, теперь мы имеем дело с традиционным и логичным понятием «страница» а не с контролерами и моделями разбросанными по всему проекту. Но поскольку .NET будет развиваться по направлению Core.Net то вряд ли Razor Page появятся в стандартном фреймворке, несмотря на то что ближайшие годы большинство проектов будет оставаться на стандартном .NET. Тем не менее можно изобразить функциональность Razor Pages и на стандартном фреймворке.
Решение на самом деле выглядит достаточно тривиально — нужно добавить в контролер следующую конструкцию:
Метод OnActionExecuting -событие жизненного цикла который вызывается перед выполнением метода контролера (имеется ввиду обработчик запроса — Action).
UpdateModel выполняет непосредственно привязку параметров запроса к свойствам (properties) модели — в данном случае свойствам класса контроллера.
Дополнительное удобство — теперь нет необходимости вообще принимать явно параметры ни типа Model ни какие другие. Хотя ничего не мешает это делать, если параметр — простой id, который будет использовать чисто как локальная переменная, но привязка параметров как свойств контролера необходима например, если нужно обеспечить персистентность страницы, о чем пойдет речь дальше.
Простой пример:
У нас есть обычная форма логина с двумя полями.
Приводить разметку нет смысла приведу только код контроллера
Как видим, в момент срабатывания события входные данные уже привязаны и готовы к использованию.
Разумеется, надо иметь ввиду что теперь возвращать как ActionResult тоже нужно контроллер ну и в шаблоне прописать имя класса контролера — типа @Model AccountController.
Как следствие такого решения упрощается и задача сохранения состояния страницы между запросами. Допустим у вас есть страница с некоей таблицей, фильтром сортировкой по столбцам и пагинацией.
Вы кликаете по фильтру модель возвращается в представление и все хорошо, но когда кликните сортировку фильтр естественно сбросится. Пагинатор сбросит и сортировку и фильтр. В WebForms состояние страницы сохранялось автоматически, в MVC приходится применять разные громоздкие решения, например склеивать все параметры и гонять их по каждому запросу, то есть на ссылку сортировки нужно повесить все параметры которые пришли перед этим с фильтра.
Подобные затруднения являются одной из причин SPA и прочего яваскриптового безумия с перетаскиванием логики и данных в браузер с вытекающими из этого тормозами браузера (особенно мобильных девайсах), прыгающими и дергающимися за каждым движением мышки страницами и увеличением трудоемкости и стоимости работ — ведь бэкенд то все равно писать в том или ином виде, упаковывать распаковывать данные пересылаемые через ajax, плюс callbac hell, усложнения отладки и так далее, и все это без практической пользы для посетителей сайта которым нет дела как написана страница.
Наиболее логичным решением является сохранение состояния страницы в сессии. Поскольку у нас все необходимые параметры уже под руками в виде свойств контроллера, все что нужно — это переопределить метод OnActionExecuted, который вызывается после обработки запроса, и упаковать нужные свойства в сессию (ключ сессии очевидно должен указывать на имя контролера).
Восстанавливаются параметры из сессии в конструкторе контролера или перед вызовом UpdateModel(this). Когда придет запрос, например сортировки то новые параметры изменятся а остальное останется нетронутым и представление будет отображено в том же виде как было отправлено.
Такое решение имеет еще одно удобство — к примеру, пользователь отсортировал таблицу, и решил какой то элемент отредактировать, открывши для этого другую страницу. Естественно он хочет вернутся в то состояние списка которое оставил а так как состояние страницы у нас в сессии, то страница восстановится автоматически. Нет никакой необходимости, как часто делают, передавать весь «вареник» параметров в страницу редактирования и обратно. Если сохранять состояние между страницами нет необходимости то состояние страницы можно хранить не в сессии а в TempData.
Надеюсь данные «лайфхаки» хоть и выглядят тривиально, будут полезны новичкам пока они не подсмотрели в интернете более неудобных и громоздких решений и решили что других не бывает.
Иными словами, Razor Pages — более вменяемое решение для веба чем MVC, теперь мы имеем дело с традиционным и логичным понятием «страница» а не с контролерами и моделями разбросанными по всему проекту. Но поскольку .NET будет развиваться по направлению Core.Net то вряд ли Razor Page появятся в стандартном фреймворке, несмотря на то что ближайшие годы большинство проектов будет оставаться на стандартном .NET. Тем не менее можно изобразить функциональность Razor Pages и на стандартном фреймворке.
Решение на самом деле выглядит достаточно тривиально — нужно добавить в контролер следующую конструкцию:
protected override void OnActionExecuting(ActionExecutingContext Context)
{
UpdateModel(this);
}
Метод OnActionExecuting -событие жизненного цикла который вызывается перед выполнением метода контролера (имеется ввиду обработчик запроса — Action).
UpdateModel выполняет непосредственно привязку параметров запроса к свойствам (properties) модели — в данном случае свойствам класса контроллера.
Дополнительное удобство — теперь нет необходимости вообще принимать явно параметры ни типа Model ни какие другие. Хотя ничего не мешает это делать, если параметр — простой id, который будет использовать чисто как локальная переменная, но привязка параметров как свойств контролера необходима например, если нужно обеспечить персистентность страницы, о чем пойдет речь дальше.
Простой пример:
У нас есть обычная форма логина с двумя полями.
Приводить разметку нет смысла приведу только код контроллера
public class AccountController : Controller
{
public string username{ get; set; }
public string userpass{ get; set; }
[HttpPost]
public ActionResult OnLogin( )
{
//некая функция проверки в БД
checklogin(username,userpass);
return View("Index",this);
}
protected override void OnActionExecuting(ActionExecutingContext Context)
{
UpdateModel(this);
}
}
Как видим, в момент срабатывания события входные данные уже привязаны и готовы к использованию.
Разумеется, надо иметь ввиду что теперь возвращать как ActionResult тоже нужно контроллер ну и в шаблоне прописать имя класса контролера — типа @Model AccountController.
Как следствие такого решения упрощается и задача сохранения состояния страницы между запросами. Допустим у вас есть страница с некоей таблицей, фильтром сортировкой по столбцам и пагинацией.
Вы кликаете по фильтру модель возвращается в представление и все хорошо, но когда кликните сортировку фильтр естественно сбросится. Пагинатор сбросит и сортировку и фильтр. В WebForms состояние страницы сохранялось автоматически, в MVC приходится применять разные громоздкие решения, например склеивать все параметры и гонять их по каждому запросу, то есть на ссылку сортировки нужно повесить все параметры которые пришли перед этим с фильтра.
Подобные затруднения являются одной из причин SPA и прочего яваскриптового безумия с перетаскиванием логики и данных в браузер с вытекающими из этого тормозами браузера (особенно мобильных девайсах), прыгающими и дергающимися за каждым движением мышки страницами и увеличением трудоемкости и стоимости работ — ведь бэкенд то все равно писать в том или ином виде, упаковывать распаковывать данные пересылаемые через ajax, плюс callbac hell, усложнения отладки и так далее, и все это без практической пользы для посетителей сайта которым нет дела как написана страница.
Наиболее логичным решением является сохранение состояния страницы в сессии. Поскольку у нас все необходимые параметры уже под руками в виде свойств контроллера, все что нужно — это переопределить метод OnActionExecuted, который вызывается после обработки запроса, и упаковать нужные свойства в сессию (ключ сессии очевидно должен указывать на имя контролера).
protected override void OnActionExecuted (ActionExecutedContext Context)
{
//сохраняем данные
}
Восстанавливаются параметры из сессии в конструкторе контролера или перед вызовом UpdateModel(this). Когда придет запрос, например сортировки то новые параметры изменятся а остальное останется нетронутым и представление будет отображено в том же виде как было отправлено.
Такое решение имеет еще одно удобство — к примеру, пользователь отсортировал таблицу, и решил какой то элемент отредактировать, открывши для этого другую страницу. Естественно он хочет вернутся в то состояние списка которое оставил а так как состояние страницы у нас в сессии, то страница восстановится автоматически. Нет никакой необходимости, как часто делают, передавать весь «вареник» параметров в страницу редактирования и обратно. Если сохранять состояние между страницами нет необходимости то состояние страницы можно хранить не в сессии а в TempData.
Надеюсь данные «лайфхаки» хоть и выглядят тривиально, будут полезны новичкам пока они не подсмотрели в интернете более неудобных и громоздких решений и решили что других не бывает.