"Конечно, это пока размахивание руками в воздухе. Если сделаете проект, зальете на какой-нибудь гитхаб/битбакет, смогу поревьюить и может дельное подсказать."
пока мой код стыдно куда то выкладывать =)) там будет ошибка на ошибке, ибо ко мне только сейчас начало приходить минимальное представление об ООП и MVC
Толстый Лорри: Хотя я не совсем внимательно прочёл ваш этот абзац:
" Верно, вы это хорошо заметили, бизнес-логика должна находиться в BL. Для какой-то специфической обработки данных нужно создавать сервис (BlogPostServeice или как-нибудь так) в BL, в который инжектися репозиторий (через интерфейс, само собой), как источник данных, и уже этот сервис прокидывать в ASP.NET-контроллер. Сервис представляет собой некоторый логический модуль в терминах нашей прикладной области, поэтому он может использовать несколько репозиториев."
Если учитывать то что вы написали, то получается надо исправить то что я написал постом выше.
1. Во-первых, Создать интерфейс для ProductService
2. Убрать из контроллера внедрение DI - IProductRepository repository, вместо неё добавить новую DI,
IProductService productService.
3. Добавить в проект Product.Domain зависомость в класс ProductService экземпляр IProductRepository repository.
4. Метод контроллера public ActionResult List() изменить на
public ActionResult List()
{
IEnumerable productListDiscount = productService.GetProductPricesWithDiscount();
// все данные GetProductPricesWithDiscount будет брать сам из репозитория, который подключается c помощью DI
}
Так будет правильнее? А пример посто выше имеет место быть? Или это котровенный говн*кодинг?
Очень прошу прочитать два моих последних коммента, обещаю после этого отстать =))))
Толстый Лорри:
"а GetProductPricesWithDiscount (получить продукты с учетом скидки, т.е. модификация сущностей из базы каким-то бизнес-правилом - скидкой) лучше убрать в сервис"
Ох спасибо за вашу неоценимую помощь, сам бы я это искал бы ещё очень долго.
Попробую собрать в кучу то что вы мне подскали и свои соображения. На примере, что вы привели с продуктами.
Получается так:
ПРОЕКТ Product.Domain
BL:
- В папке "Entities", создаём сущность Product, со свойствами (Id, Price, Name).
- В папке "Abstract" создаём интерфейс IProductRepository, со свойством IEnumerable Products { get; }
- (вот тут сомнения, так как у Фримана её нигде не было) Создаём папку "Services", в ней класс ProductService с методом "public IEnumerable GetProductPricesWithDiscount(IEnumerable list)"
вроде с бизнес логикой всё
Далее
DAL
- В папке создаём "Concrete" класс контекста
public class EFDbContext : DbContext
{
public EFDbContext() : base("name=EFDbContext") { }
public virtual DbSet Products { get; set; }
}
- Здесь же создаём файл и реализуем интерфейс
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IEnumerable Products
{
get { return context.Products; }
}
}
Проект Product.WebUI Слой UI:
- В папке Controllers создаём
public class ProductsController : Controller
{
IProductRepository repository; // создаём экземпляр с помощью инъекции зависимости
ProductService productService = new ProductService(); // сразу инициализируем, чтобы иметь возможность в экшене использовать скидку на товар
Судя по нему, свой метод, который модифицирует текст статьи CreateTable, я бы мог поместить в класс "BlogPostRepository", который находится в DAL. Плюс в том, что его экземпляр и так и так будет создаваться в контроллере, и его легко использоваться
Но также есть сомнения, не правильнее ли будет такие специфичные методы обработки перенести с Business logic?, ведь вы пишите что там могут находиться сервисы и их реализации? " сервисы (интерфейсы и реализации, которые работают с репозиториями)"
Или вы подразумеваете что то иное под сервисами?
По поводу книги Фримна, сразу скажу, что я счастливый обладатель 5го издания в печатной форме, и в данный момент постигаю азы ASP MVC именно по ней. Для меня эта книга - просто находка.
Но всё же, на некоторые вопросы я там не нашёл ответ (или может быть пока не нашёл, так как нахожусь сейчас на 18 главе (Фильтры). Делаю свой блог именно по предложенной в книге модели.
Правильно ли я понимаю, что в принципе запрос repository.Articles .FirstOrDefault(p => p.Url == url); можно поместить в DAL (вы написали, что манипуляции с БД размещаются именно там). Но почему тогда Фримен в своём приложении SpotsStore так не делает, и размещает все запросы к БД прямо в контроллерах?
Ещё вопрос по поводу BL, я так понимаю что все сущности, которые там находятся должны иметь только лишь свойства? Метод CreateTable там размещать будет не правильно?
Вы пишите:
> BL содержит: доменные модели, интерфейсы для репозиториев, сервисы (интерфейсы и реализации, которые работают с репозиториями).
т е тут и может быть размещён запрос на извлечение записи из БД?
Также Вы пишите:
> UI (для ASP.NET MVC) содержит: собственно веб-проект с котроллерами *Controller.cs (Controllers), вьюшками *.cshtml (Views), вью-модели *.cs (Models, те специфические модели, которыми типизируются
Т е это и есть модели представления? (У Фримана есть такая - ProductsListView). А в эту модель я могу запихнуть свой метод - CreateTable
Виктор, можно задать вам ещё такой вопрос, правда не совсем по теме.
Создаю представление Article, в нём есть форма для того чтобы пользователь мог оставить комментарий
В форме есть скрыто поле "Html.Hidden("ArticleId", Model.ID);"
Это поле нужно для того, чтобы в базе привязать комментарий к определённой статье. Вопрос вот в чем.
Получается, что в контроллере, который обрабатывает этот пост запрос имеются поля комментариев (автор и текст коммента), а также ID статьи, который передаётся скрытым полем.
И поскольку в сущности Comment такого свойства поля как "int ArticleID" нету (вместо него public Article Article { get; set; }) приходится делать лишьний запрос к базе, чтобы извлечь Article. А только потом отправить комментарий в базу.
Вопрос вот в чём, как за один запрос в контроллере добавить комментарий, зная ID статьи, для которой он оставлен?
получается, эта библиотека сама создаёт класс-делегат этого типа, и именно поэтому метод Setup смог принять такой делегат? m => m.ApplyDiscount(It.IsAny())
Т е m => m.ApplyDiscount(It.IsAny()) является чем то в стиле анонимного делегата? А где тогда происходит объявление самого класса-делегата? Или это просто какое то сокращение? А компилятор всё создаст за нас?
Правильно ли я понимаю что строка
mock.Setup(m => m.ApplyDiscount(It.IsAny()))
равносильна
public delegate какойтотип MyDelegate(какойтотиппараметра m);
public какойтотип Method(какойтотиппараметра m)
{
return m.ApplyDiscount(It.IsAny());
}
пока мой код стыдно куда то выкладывать =)) там будет ошибка на ошибке, ибо ко мне только сейчас начало приходить минимальное представление об ООП и MVC
Спасибо, за такую неоценимую помощь!