Pull to refresh

Добавляем функциональность Razor Pages в стандартный .NET

Reading time4 min
Views13K
Razor Pages — новая фича, появившаяся в Core.Net 2.0. Razor Page — это страница, состоящая из стандартной разметки (View) и бэкенд класса. В каком то смысле напоминает Web Forms только без поддержки сохранения состояния. Преимущество такого решения очевидно — мы избавляемся от ненужной прослойки — модели страницы (модель данных в виде например Entity это само собой). Бэкенд страницы является и контроллером и моделью — классика ООП — инкапсуляция данных и методов работы с ними в одном объекте. В конце концов модель страницы — это просто класс, нет никаких причин почему этим классом не может быть контроллер.

Иными словами, 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.

Надеюсь данные «лайфхаки» хоть и выглядят тривиально, будут полезны новичкам пока они не подсмотрели в интернете более неудобных и громоздких решений и решили что других не бывает.
Tags:
Hubs:
+5
Comments31

Articles

Change theme settings