Создаем доменную модель
Мы начнем с создания доменной модели. Практически все в приложении 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
имитацией объекта.