ASP.NET MVC. Перехватываем нулевую модель (null model handling).
public class AbstractController : Controller { public ActionResult Index() { var model = new SomeModel(); model.Property1 = SomeService1.GetProperty1(); model.Property2 = AnotherService.GetProperty2(); SomeStrangeHelper.DoSomethingWithModel(model); ... return View(model); } }
public ActionResult Index() { var model = new SomeModel(); model.Property1 = SomeService1.GetProperty1(); if(model.Property1 == null) { return RedirectToAction("FarAway", "AnyController"); } model.Property2 = AnotherService.GetProperty2(); if(model.Property2 == QweHelper.GetValue(DateTime.Now)) { throw new Exception("something happened"); } SomeStrangeHelper.UpdateModel(model); ... return View(model); }
, даже несмотря на то, что все эти точки могут складываться в глубокую «матрешку» из всяких условий — это еще цветочки, ягодки начинаются на вьюхе — различные NullReference exceptions из-за того, что одно из свойств мы забыли (или забили) заполнить, или отложенное свойство начало разворачивать свой Linq`овский запрос и грохнуло вьюху, вообщем вариантов много. Решение одно — контроллер должен содержать только логику по передаче модели во вьюху. Из-за этого должен появиться некоторый сервис, на который будет распространяться достаточно жесткое требование — такой сервис возвращает валидную c точки зрения вьюхи модель, либо null.
Но что значит, если модель равна null ? Спорить на эту тему можно долго, я буду рассматривать вариант, когда это означает, что запрашиваемый ресурс не найден, в контексте веба это равносильно ошибке 404 — NotFound. Т.е. нулевая модель означает, что мы должны вернуть HttpNotFound(). Сделать просто можно так:
public ActionResult Index() { var model = Services.GetModel(); return model == null ? (ActionResult)HttpNotFound() : View(); }
, а можно сделать ActionFilterAttribute. Такой атрибут, должен проверять результат экшена, но до того момента, как он будет полностью выполнен, в этом нам поможет метод OnResultExecuting, в отличие от OnResultExecuted, он не кинет исключение при нулевой модели, потому что еще не завершился полностью. Ниже приведен код этого атрибута, все просто:
public class HandleNullModelAttribute : ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { var result = filterContext.Result as ViewResult; if (result != null) { if (result.Model == null) { filterContext.Cancel = true; // Отменяем текущий результат. filterContext.Result = new HttpNotFoundResult(); // Устанавливаем новый результат. filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext); // Выполняем. } } } }
Пример использования:
public class SitemapController : Controller { [HandleNullModel] public ContentResult Index() { var model = SitemapGenerator.GenerateSitemap(); return Content(model, "text/xml"); } }
Что можно сделать еще — расширить атрибут для возможности валидации ViewData и ViewBag, а это уже немного сложнее. По определенным причинам я не буду приводить пример такого расширения.
Свежие комментарии