Должны контроллеры в вызове веб-приложения MVC ASP.NET репозитории, сервисы или оба?

Давайте сделаем педантичный, потому что есть различия, которые могут действительно повлиять на поведение вашего кода. Из комментариев, сделанных к статье «Old New Thing» , взята большая часть из следующих соображений.

Иногда память, возвращаемая новым оператором, будет инициализирована, а иногда она не будет в зависимости от того, является ли тип, который вы новичок, представляет собой POD (простые старые данные) , или если это класс, который содержит элементы POD и использует созданный компилятором конструктор по умолчанию.

  • В C ++ 1998 существует 2 типа инициализации: нуль и значение по умолчанию
  • В C ++ 2003 добавлена ​​инициализация 3-го типа, инициализация значения.

Предположим:

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

В компиляторе C ++ 98 должно произойти следующее:

  • new A - неопределенное значение
  • new A() - zero-initialize
  • new B - конструктор по умолчанию (B :: m не инициализирован)
  • new B() - конструкция по умолчанию (B :: m неинициализирована )
  • new C - конструкция по умолчанию (C :: m инициализируется нулем)
  • new C() - конструкция по умолчанию (C :: m инициализируется нулем)

В компиляторе, совместимом с C ++ 03, все должен работать следующим образом:

  • new A - неопределенное значение
  • new A() - значение-инициализация A, которая является нулевой инициализацией, поскольку это POD.
  • new B - default-initializes (оставляет B :: m uninitialized)
  • new B() - значение-инициализирует B, который нуль инициализирует все поля, поскольку его по умолчанию ctor генерируется компилятором в противоположность определяемый пользователем.
  • new C - по умолчанию инициализирует C, который вызывает значение по умолчанию ctor.
  • new C() - значение инициализирует C, который вызывает значение по умолчанию ctor.

Итак, во всех версиях C ++ существует разница между new A и new A(), поскольку A является POD.

И есть разница в поведении между C ++ 98 и C ++ 03 для случая new B().

Это один из пыльных углов C ++, который может свести вас с ума. Когда вы строите объект, иногда вам нужны / нужны парнеры, иногда вы их абсолютно не можете, и иногда это не имеет значения.

19
задан Fabian Steeg 23 January 2009 в 10:42
поделиться

7 ответов

Ваша бизнес-логика должна инкапсулироваться в бизнес-объектах - если у Вас есть объект Порядка (и Вы делаете, не так ли?), и бизнес-правило указывает, что электронное письмо должно быть послано, когда Порядок выполняется, затем Ваш Выполнять метод (или, если более соответствующее, метод set для IsFulfilled) должен инициировать то действие. У меня, вероятно, была бы конфигурационная информация, которая указала на бизнес-объект на соответствующий почтовый сервис для приложения, или в более общем плане к "notifier" сервису так, чтобы другие типы уведомления могли быть добавлены когда/при необходимости.

0
ответ дан 30 November 2019 в 03:48
поделиться

Это могло бы казаться раздражающим для наблюдения партии этого в бизнес-услугах:

public Customer GetCustomer(int id)
{
     return customerRepository.Get(id);
}

И естественно иметь сильное желание обойти сервис. Но Вы более обеспечены в конечном счете разрешение Вашего промежуточного звена бизнес-услуг между контроллерами и репозиториями.

Теперь, для очень простого приложения типа CRUD, у Вас могли быть свои контроллеры, используют репозитории непосредственно вместо того, чтобы пройти бизнес-услуги. У Вас могло все еще быть что-то как EmailerService, но IMO когда дело доходит до выборки и выполнения вещей с объектами, лучше всего не к бизнес-услуге смешивания и подгонки и вызовам репозитория в Ваших контроллерах.

Что касается наличия объектов (бизнес-объекты) обслуживания вызовов или любые компоненты инфраструктуры, я не сделал бы этого. Я предпочитаю сохранять объекты ПОСТЕПЕННО и свободный от зависимостей.

1
ответ дан 30 November 2019 в 03:48
поделиться

Ваши контроллеры (в проекте MVC) должны называть Ваши объекты в Сервисном проекте. Сервисный проект состоит в том, где вся бизнес-логика обрабатывается.

А хороший пример - это:

public ActionResult Index()
{
    ProductServices productServices = new ProductServices();

    // top 10 products, for example.
    IList<Product> productList = productServices.GetProducts(10); 

    // Set this data into the custom viewdata.
    ViewData.Model = new ProductViewData
                         {
                             ProductList = productList;
                         };

    return View();
}  

или с Внедрением зависимости (мой fav)

// Field with the reference to all product services (aka. business logic)
private readonly ProductServices _productServices;

// 'Greedy' constructor, which Dependency Injection auto finds and therefore
// will use.
public ProductController(ProductServices productServices)
{
    _productServices = productServices;
}

public ActionResult Index()
{
    // top 10 products, for example.
    // NOTE: The services instance was automagically created by the DI
    //       so i din't have to worry about it NOT being instansiated.
    IList<Product> productList = _productServices.GetProducts(10); 

    // Set this data into the custom viewdata.
    ViewData.Model = new ProductViewData
                         {
                             ProductList = productList;
                         };

    return View();
}

Теперь.. каков Сервисный проект (или что такое ProductServices)? это - библиотека классов с Вашей бизнес-логикой. Например.

public class ProductServices : IProductServices
{
    private readonly ProductRepository _productRepository;
    public ProductServices(ProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IList<Product> GetProducts(int numberOfProducts)
    {
        // GetProducts() and OrderByMostRecent() are custom linq helpers...
        return _productRepository.GetProducts()
            .OrderByMostRecent()
            .Take(numberOfProducts)
            .ToList();
    }
}

, но это могло бы быть всеми таким образом хардкор и путающий..., таким образом, простая версия класса ServiceProduct могла быть (но я действительно не рекомендую)...

public class ProductServices
{
    public IList<Product> GetProducts(int numberOfProducts)
    {
        using (DB db = new Linq2SqlDb() )
        {
            return (from p in db.Products
                    orderby p.DateCreated ascending
                    select p).Take(10).ToList();
        }
    }
}

, Таким образом, там Вы идете. Вы видите, что вся логика находится в Сервисных проектах, что означает, что можно снова использовать тот код в других местах.

, Где я изучал это?

От Rob Conery медиа MVC StoreFront и учебные руководства .Лучше не бывает. Его учебные руководства объясняют (что я сделал) в хороших деталях с примерами кода полного решения. Он использует Внедрение зависимости, которое является SOO kewl теперь, когда я видел, как он использует его в MVC.

HTH.

26
ответ дан 30 November 2019 в 03:48
поделиться

Если Вы собираетесь иметь бизнес-слой, то я думаю, что это лучше иметь только , бизнес-слой говорит со слоем данных. Я могу понять, почему в простом варианте использования, у Вас был бы уровень представления (контроллер) говорят со слоем данных непосредственно, но после того как Вы определяете, что потребность в изолированном бизнес-слое, затем смешивая использование двух в более высоких уровнях добирается, чтобы быть опасной.

, Например, что, если контроллер A называет метод в бизнес-слое для выборки Списка Объекта (и этот метод применяет бизнес-правила - возможно, некоторая фильтрация или сортировка), но затем Контроллер B приходит, нуждается в той же части данных, но забывает о бизнес-слое и называет слой данных непосредственно?

1
ответ дан 30 November 2019 в 03:48
поделиться

Я не уверен в использовании сервисов для этого.

Насколько я понимаю, один из принципов DDD (на котором я читаю в данный момент) - то, что Объекты области организованы в Агрегаты и что при создании экземпляра Совокупного корня он может только непосредственно иметь дело с объектами в Агрегате (чтобы помочь поддержать ясное чувство ответственности).

Создание Агрегата должно осуществить любые инварианты и т.д.

Взятие примера Клиентского класса, Клиент мог бы быть Совокупным корнем, и другой класс в Агрегате мог бы быть Адресом.

Теперь, если Вы хотите создать нового Клиента, необходимо смочь сделать это использование или Клиентский конструктор или фабрика. Выполнение этого должно возвратить объект, который полностью функционален в Совокупной границе (таким образом, это не может иметь дело с продуктами, поскольку это не часть Агрегата, но это может обработать Адреса).

база данных является вопросом второстепенной важности и только играет роль для сохранения Агрегата к базе данных или получения его от базы данных.

, Чтобы постараться не взаимодействовать через интерфейс с базой данных непосредственно можно создать интерфейс Repository (как обсуждено), который приведенный пример Клиента (который включает ссылку на Адрес) должен смочь сохранить Агрегат к базе данных.

Дело в том, что интерфейс Repository ЯВЛЯЕТСЯ частью Вашей модели предметной области / слой (Реализация Репозитория не). Другой фактор - то, что репозиторий, вероятно, должен закончить тем, что звонил, то же "создают" метод, как будто Вы создавали новый объект (для поддержания инвариантов и т.д.). При использовании конструктора, это достаточно просто, поскольку Вы закончите тем, что вызвали конструктора, когда репозиторий "создаст" объект из данных так или иначе.

прикладной уровень может непосредственно общаться с доменом (включая интерфейс репозитория).

Поэтому, если Вы хотите создать новый экземпляр объекта, Вы можете, например,

Customer customer = new Customer();

, Если приложение должно получить экземпляр клиента из репозитория, нет никакой конкретной причины, о которой я могу думать для него для не вызова...

Customer customer = _custRepository.GetById(1)

или...

Customer customer = _custRepository.GetByKey("AlanSmith1")

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

я думаю, что сервисы должны быть зарезервированы для того, когда "вещью", с которой Вы пытаетесь работать просто, не является объект. Большинство правил (ограничения и т.д.) может быть записано как часть самого Объекта области.

А хороший пример находится в DDD Быстро PDF, который я читаю в данный момент. Там у них есть ограничение на объект Книжной полки, посредством чего можно только добавить столько книг, сколько полка может содержать.

Вызов метода AddBook на объекте BookShelf проверяет, что место является свободным прежде, чем добавить книгу к набору BookShelf Книжных объектов. Простой пример, но бизнес-правило осуществляется самим Объектом области.

я не говорю, что любое вышеупомянутое корректно между прочим! Я пытаюсь получить голову вокруг всего этого в данный момент!

5
ответ дан 30 November 2019 в 03:48
поделиться

Помогло бы, могли ли мы прекратить видеть этот пример много раз...

public ActionResult Index()
{
  var widgetContext = new WidgetDataContext();
  var widgets = from w in widgetContext.Widget
                select w;
  return View(widgets);
}

я понимаю, что это не полезно Вашему вопросу, но это, кажется, часть большого количества демонстрационного программного обеспечения, что я думаю, может вводить в заблуждение.

0
ответ дан 30 November 2019 в 03:48
поделиться

Ну, это действительно зависит от вас, я предпочитаю, чтобы контроллеры были как можно более простыми, и чтобы заархивировать это, мне нужно инкапсулировать бизнес-логику на отдельном уровне, и вот большой вещь, в основном у вас есть 2 варианта, если вы используете Linq2SQL или Entity Framework:

  • Вы можете использовать методы расширения и частичный класс для проверки ваших моделей непосредственно перед сохранением изменений (хуки метод, вы можете увидеть пример это в образце Nerdinner Скоттом Гу).

  • Другой способ (и мой любимый, потому что я чувствую больше контроля над потоком приложения), заключается в использовании полностью отдельный слой для бизнеса логика, такая как уровень служб (вы можете увидеть этот подход в серии уроки Стивена Вальтера в asp.net/mvc zone).

С помощью этих двух методов вы получите СУХОЙ и очистите ваши контроллеры, которые в остальном были беспорядочными.

1
ответ дан 30 November 2019 в 03:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: