Главная страница   /   7.2. Создаем доменную модель (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

7.2. Создаем доменную модель

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

Поскольку мы разрабатываем приложение для электронной коммерции, очевидно, самой главной доменной сущностью у нас будет товар. Создайте новую папку под названием Entities в проекте SportsStore.Domain, а в ней - новый класс C# под названием Product. Искомая структура показана на рисунке 7-4.

Рисунок 7-4: Создаем класс Product

Содержание класса Product вам уже известно, так как мы собираемся использовать тот же класс, что и в предыдущих главах. Отредактируйте файл класса Product, чтобы он соответствовал листингу 7-3.

Листинг 7-3: Файл класса Product
namespace SportsStore.Domain.Entities
{
	public class Product
	{
		public int ProductID { get; set; }
		public string Name { get; set; }
		public string Description { get; set; }
		public decimal Price { get; set; }
		public string Category { get; set; }
	}
}

Мы следуем соглашению, по которому мы определяем доменную модель в отдельном проекте Visual Studio, а это означает, что класс должен быть помечен как public. Следовать этому соглашению не обязательно, но мы считаем, что оно помогает сохранять изоляцию модели от контроллеров.

Создаем абстрактное хранилище

Разумеется, нам нужно каким-то образом получать объекты Product из базы данных. Как мы уже объяснили в главе 3, мы хотим держать логику хранения изолированно от объектов доменной модели, и для этого мы будем использовать шаблон хранилища. Сейчас мы не будем думать о том, как мы собираемся реализовать хранение, и начнем с того, что определим для него интерфейс.

Создайте новую папку верхнего уровня в проекте SportsStore.Domain под названием Abstract и новый интерфейс под названием IProductsRepository, содержание которого показано в листинге 7-4. Чтобы добавить новый интерфейс, кликните правой кнопкой мыши папку Abstract, выберите Add - New Item и шаблон Interface.

Листинг 7-4: Файл интерфейса IProductRepository
using System.Linq;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Abstract
{
	public interface IProductRepository
	{
		IQueryable<Product> Products { get; }
	}
}

Здесь используется интерфейс IQueryable<T>, который позволяет получить последовательность объектов Product и не требует указаний на то, как и где хранятся данные или как следует их извлекать. Класс, который использует интерфейс IProductRepository, может получить объекты Product, не зная того, где они содержатся или каким образом будут ему поставлены. Это и есть суть шаблона хранилища. Мы будем возвращаться к этому интерфейсу на протяжении всего процесса разработки, чтобы добавлять новые функции.

Создаем имитированное хранилище

Определив абстрактный интерфейс, мы можем реализовать механизм хранения и подключить его к базе данных. Мы сделаем это позже в этой главе. Чтобы начать писать другие части приложения, мы собираемся создать имитированную реализацию интерфейса IProductRepository. Это мы сделаем в методе AddBindings класса NinjectControllerFactory в проекте SportsStore.WebUI, как показано в листинге 7-5.

Листинг 7-5: Добавляем имитированную реализацию IProductRepository
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Ninject;
using SportsStore.Domain.Entities;
using SportsStore.Domain.Abstract;
using System.Collections.Generic;
using System.Linq;
using Moq;

namespace SportsStore.WebUI.Infrastructure
{
	public class NinjectControllerFactory : DefaultControllerFactory
	{
		private IKernel ninjectKernel;
		public NinjectControllerFactory()
		{
			ninjectKernel = new StandardKernel();
			AddBindings();
		}

		protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
		{
			return controllerType == null
				? null
				: (IController)ninjectKernel.Get(controllerType);
		}
		private void AddBindings()
		{
			Mock<IProductRepository> mock = new Mock<IProductRepository>();
			mock.Setup(m => m.Products).Returns(new List<Product> {
					new Product { Name = "Football", Price = 25 },
					new Product { Name = "Surf board", Price = 179 },
					new Product { Name = "Running shoes", Price = 95 }
				}.AsQueryable());

			ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);
		}
	}
}

Для этого дополнения мы должны были добавить в файл несколько пространств имен, но процесс, который создает имитированное хранилище, использует те же самые техники Moq, которые мы рассмотрели в главе 4. AsQueryable является методом расширения LINQ, который преобразует IEnumerable<T> в IQueryable<T>. Это необходимо для соответствия сигнатуры интерфейса.

Мы используем метод ToConstant, потому что хотим, чтобы Ninject возвращал имитацию объекта, когда он получает запрос от реализации интерфейса IProductRepository:

ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);

Вместо того, чтобы каждый раз создавать новый экземпляр реализации объекта, Ninject всегда будет отвечать на запросы интерфейса IProductRepository имитацией объекта.