Главная страница   /   15.5. Представление модели через пользовательский интерфейс (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

15.5. Представление модели через пользовательский интерфейс

Теперь, когда доменная модель и инфраструктура NHibernate заданы и функционируют, мы можем снова перенести наше внимание к ASP.NET MVC проекту. Мы оставили проект близким к используемому по умолчанию шаблону проекта с тем, чтобы сохранить его простоту, а также явно идентифицировать дополнительные компоненты, необходимые для сохранения каждого посетителя сайта. Рисунок 15-8 демонстрирует структуру UI-проекта.

Рисунок 15-8: Дополнительные компоненты проекта выделены цветом. Мы добавили несколько файлов для фиксации и отображения посетителей.

Как вы помните (из рисунка 15-1), в верхней части каждой страницы сайта демонстрируются недавние посетители сайта. Для того чтобы распределить это представление между всеми страницами, мы подключили частичное представление к мастер-странице, Site.Master. Мы рассматривали эту возможность в главе 3, поэтому не будем снова рассматривать ее подробно.

На самом верхнем уровне мы добавили атрибут фильтра действий к каждому контроллеру. Если сайт содержит множество контроллеров, мы предполагаем, что необходимо ввести пользовательский ControllerActionInvoker для всех контроллеров и добавить фильтр для всех контроллеров. В этом примере проект содержит только HomeController, который продемонстрирован в следующем листинге. Обратите внимание на фильтры действий, применяемые на уровне класса.

Листинг 15-11: Фильтры действий, применяемые к контроллерам для поддержания разделенности понятий
using System.Web.Mvc;
namespace UI.Controllers
{
	[HandleError]
	[VisitorAdditionFilter(Order = 0)]
	[VisitorRetrievalFilter(Order = 1)]
	public class HomeController : Controller
	{
		public ActionResult Index()
		{
			ViewBag.Message = "Welcome to ASP.NET MVC!";
			return View();
		}
		public ActionResult About()
		{
			return View();
		}
	}
}

Строка 5: Применяет VisitorAdditionFilter

Строка 6: Применяет VisitorRetrievalFilter

Мы ввели два фильтра, VisitorAdditionFilter и VisitorRetrievalFilter. Мы применили необязательный параметр Order для того, чтобы убедиться, что они выполняются в запланированном порядке. Порядок, в котором атрибуты применяются к классу, не является гарантированным порядком выполнения.

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

Листинг 15-12: Взаимодействие фильтров действий с доменной моделью
using System.Web.Mvc;
using Core;
namespace UI
{
	public class VisitorAdditionFilter : ActionFilterAttribute
	{
		private readonly IVisitorRepository _repository;

		public VisitorAdditionFilter(IVisitorRepository repository)
		{
			_repository = repository;
		}

		public VisitorAdditionFilter() 
			: this(new VisitorRepositoryFactory().BuildRepository())
		{
		}

		public override void OnResultExecuting(ResultExecutingContext filterContext)
		{
			var builder = new VisitorBuilder();
			Visitor visitor = builder.BuildVisitor();
			_repository.Save(visitor);
		}
	}

	public class VisitorRetrievalFilter : ActionFilterAttribute
	{
		private readonly IVisitorRepository _repository;
		public VisitorRetrievalFilter(IVisitorRepository repository)
		{
			_repository = repository;
		}

		public VisitorRetrievalFilter()
			: this(new VisitorRepositoryFactory().BuildRepository())
		{
		}

		public override void OnResultExecuting(ResultExecutingContext filterContext)
		{
			Visitor[] visitors = _repository.GetRecentVisitors(10);
			filterContext.Controller.ViewData[Constants.ViewData.VISITORS]= visitors;
		}
	}
}

Строка 15, 36: Создает репозиторий с помощью фабрики

Строка 19, 40: Выполняет работу в OnResultExecuting

Строка 22-23: Сохраняет новый Visitor

Строка 42-43: Хранит недавних посетителей во ViewData

Каждый фильтр довольно прост. Большая часть кода нужна всего лишь для управления зависимостью от IVisitorRepository и создания репозитория из фабрики. Три строки, которые представляют интерес, находятся в методе OnResultExecuting. Мы создаем посетителя и сохраняем его. Затем мы получаем недавних посетителей и помещаем их во ViewData. Класс VisitorBuilder не продемонстрирован, но он довольно прост, конструирует Visitor и наполняет его информацией из HttpRequest.

Следующий представляющий интерес файл – это частичное представление Visitors.cshtml, расположенное в /Views/Shared/Visitors.cshtml.

Листинг 15-13: Отображает недавних посетителей
@model Core.Visitor[]
<div style="text-align: left">
	<h3>Recent Visitors</h3>
	@foreach (var visitor in ViewData.Model)
	{
		@visitor.VisitDate @:-
		@visitor.IpAddress @:-
		@visitor.LoginName @:-
		@visitor.PathAndQuerystring <br />
		@visitor.Browser <hr />
	}
</div>

Это частичное представление добавляется на страницу через мастер-страницу. Ожидается, что список посетителей будет располагаться в ViewData.Model с тем, чтобы список мог бы отображаться способом по умолчанию. В верхней части мастер-страницы следующий код просто передает список посетителей в частичное представление:

<div id="footer">
	@{
		var partialName = Constants.Partials.VISITORS;
		var viewData = ViewData[Constants.ViewData.VISITORS];
	}
	@Html.Partial(partialName, viewData)
</div>

Мы используем константы для того, чтобы представления не содержали продублированного строкового текста. Поскольку информация о входе в систему и отображении посетителей является сквозной в рамках всего приложения, мы предприняли шаги для того, чтобы факторизировать логику с тем, чтобы она могла совместно использоваться всеми контроллерами приложения.

Давайте повторим то, что мы проделали:

  • Поместили логику сохранения за рамки интерфейса, который не принадлежит к UI-проекту
  • Использовали фильтры действий с тем, чтобы ни один единичный контроллер не был ответственен за знание того, как выполнять интеграцию с IVisitorRepository
  • Создали частичное представление для того, чтобы иметь макет недавних посетителей
  • Передали полномочия частичному представлению мастер-страницы с тем, чтобы индивидуальным представлениям не приходилось заботиться об отображении информации о посетителе

Теперь все находится на своих местах и может быть объединено в единое целое.