Предположим, что в нашей власти оказался достаточно крупный программный проект, в котором есть очень много полезных функций, выводящих очень много разной табличной информации из большой-большой базы. Напрашивается желание выборку по базе производить (и выводить на экран) в виде, удобном пользователю. То есть, постранично.
Общая организация интуитивно ясна - контроллеру в качестве параметра номер страницы, которую мы хотим получить, он выбирает информацию из базы для этой страницы и вызывает соответствующее представление. Имеем url навроде
http://localhost/Reports/ImportantInfo?userId=3&page=4И имеем определённый упс навроде
http://localhost/Reports/ImportantInfo?userId=3Начинаются пляски с бубном:
- public class ReportsController : Controller
- {
- public ActionResult ImportantInfo(int userId, int? page)
- {
- if (!page.HasValue)
- {
- return View("Error404");
- // или
- page = 0;
- }
- // собственно, сам контроллер.
- }
- }
Проблема в том, что подобный код приходится вставлять в каждый Action Method, работающий с пагинацией. Дублирование кода - это плохо.Возьмём другую ситуацию. Предположим, к ряду Action Method-ов (какой-нибудь /Admin/Settings и ещё тонна других) необходимо предоставить доступ только пользователю с правами администратора. Опять, в каждом Action Method пишем проверку на то, является ли текущий пользователь администратором. Опять дублирование кода.
Возьмём третью ситуацию. Action Method отдаёт какой-то JSON-объект для аяксовой начинки, и соответственно его не должен вызывать никто никак кроме как через аякс. Вновь пишем:
- public class AllAjaxController : Controller
- {
- public JsonResult ImportantInfo(int userId, int? page)
- {
- if (Request.IsAjaxRequest())
- {
- // бла-бла-бла
- }
- }
- }
Подобных примеров можно придумать массу, и они имеют одно простое решение, опирающееся на мощный элемент .NET - атрибуты. И в частности в MVC - на ActionFilterAttribute.
ActionFilterAttribute, примененный к какому-либо действию, имеет два забавных метода - OnActionExecuting() и OnActionExecuted(), которые автоматически вызываются, соответственно, до и после выполнения самого действия контроллера.
Рабочий пример с пагинацией:
- public sealed class PageMethodAttribute : ActionFilterAttribute
- {
- private const int DefaultNumber = 0;
-
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- base.OnActionExecuting(filterContext);
- // в ActionParameters попадают все параметры, указанные после знака ? в урле. Нету - добавим.
- if (!filterContext.ActionParameters.ContainsKey("page"))
- {
- filterContext.ActionParameters.Add("page", null);
- }
- if (filterContext.ActionParameters["page"] == null)
- {
- filterContext.ActionParameters["page"] = DefaultNumber;
- }
- }
- }
После этого наш Action Method ImportantInfo (и все остальные того же рода) начинает выглядеть так:
- public class ReportsController : Controller
- {
- [PageMethod]
- public ActionResult ImportantInfo(int userId, int page)
- {
- // собственно, сам контроллер.
- }
- }
Комментариев нет:
Отправить комментарий