Как да обработвам бизнес правила, когато използвам инжектиране на зависимости и модел на хранилище в контролера?

Така че 99% от всички DI примери, използващи модела на Repository с MVC (или Web API), показват нещо подобно на това по-долу в действие на контролер (изпуснат код за инжектиране на конструктор за _repository). Проблемът е, че има предположение, че нищо не трябва да се обработва първо (като правила) и започването на постоянство възниква незабавно:

public ActionResult Create(Person person)
{
    if (ModelState.IsValid)
    {
      _repository.Add(person);
    }

    return View(person);
}

Проблемът е, какво ще стане, ако трябва да обработя правила в слоя на домейна, преди да запазя обекта person? Очевидно не правя тази логика в контролера, а по-скоро имам нужда от нея в слоя на домейна. Кой вариант по-долу е по-добър:

Опция 1: Преместете всички подробности за постоянство в хранилището, което ще бъде извикано в домейна/бизнес слоя, и изтеглете от контролера. Актуализираният код ще изглежда така:

if (ModelState.IsValid)
{
  using (busniessLogic = new MyApp.BusniessLogic(_repository))
  {
       busniessLogic.ProcessRulesAndSavePerson(person);
  }
}

Слоят на домейна може да има метод като този:

public void ProcessRulesAndSavePerson(Person person)
{
   //process some rules...

   if(rules = true)
   {
     //use injected repository to add now that rules have passed
     _repository.Add(person)
   }
}

Опция 2: Запазете същото като сега в контролера, но просто направете извикване, за да обработите правилата, преди да запазите в хранилището. Актуализираният код е като по-долу:

if (ModelState.IsValid)
{
  using (busniessLogic = new MyApp.BusniessLogic())
  {           
       busniessLogic.ProcessRulesAboutPerson(person);
       _repository.Add(person)
  }
}

Отворен съм и за други идеи, но клоня към Вариант №1. Обичам да поддържам контролера тънък и просто да предавам инжектирания _repository към слоя, който го изисква.

Оценява се всяка помощ по този въпрос, благодаря!


person atconway    schedule 14.01.2013    source източник


Отговори (2)


И двете опции ще създадат зависимост от процесора на бизнес логиката, винаги трябва да внимавате, когато използвате ключовата дума new, тъй като когато се опитвате да тествате модулно вашия метод, почти винаги ще се сблъскате с проблеми и това проваля целта на инжектирането на зависимости.

По-добре е да създадете услуга, която обработва сложна бизнес логика и да я инжектирате във вашия контролер. Ако по-голямата част от вашата логика е сложна, просто бих пропуснал предаването на хранилището към контролера заедно и просто бих разчитал на услугата да се справи с всичко вместо мен.

Контролер:

public MyController(IPersonService personService) 
{
    _personService = personService;
}

public ActionResult Create(Person person)
{
    if (ModelState.IsValid)
       _personService.Create(person);
    else
       ......
}

PersonService:

public PersonService(IPersonRepository repo) 
{
    _repo = repo;
}

public int Create(Person person)
{
    //businesslogic
    return _repo.Add(person);
}
person Bassam Mehanni    schedule 14.01.2013
comment
Слоят на услугата може да бъде просто .dll правилно? Това означава ли, че всички мои услуги/бизнес методи трябва да бъдат дефинирани от интерфейс? Мисля, че отговорът е „да“, защото в противен случай не мога да инжектирам екземпляр в контролера, нали? - person atconway; 14.01.2013
comment
@atconway точно! и така или иначе бихте искали интерфейс, по този начин можете лесно да тествате своя контролер, като инжектирате макет в конструктора на контролера (това е основната причина, поради която използваме DI на първо място) - person Bassam Mehanni; 14.01.2013
comment
Харесва ми да използвам слоя за услуги; избягвани досега, но достатъчно прости и прочетени много пъти. И така, ето моите слоеве: UI (MVC), Service Layer, Models/Entities Layer, Repository. Така че, ако използвам тази настройка и бизнес логиката е в моя сервизен слой, тогава моят моделен слой наистина са само DTO. В този случай използвам ли модел на анемичен домейн? Трябва ли да преместя бизнес логиката от слоя услуга към слоя Модели? - person atconway; 14.01.2013
comment
Има много неща напред-назад по тази тема, аз лично предпочитам интелигентните модели до известна степен (ако моят модел взаимодейства с други модели, обикновено бих избрал услуга. Няма правилен начин, това е каквото има смисъл да Вие сте прав, можете или да използвате услуги, или по-интелигентни модели на домейни! - person Bassam Mehanni; 14.01.2013
comment
Бихте ли казали, че е ОК да има както слой за стройни модели и слой за услуги с бизнес логика? Използвам EF с генерирани POCO класове и не ме притеснява, ако слоят Models е предимно DTO. Предполагам, че ако вместо това извадя слоя на услугата, той се превръща в нещо като прокси, което просто предава повиквания без никаква бизнес логика, нали? - person atconway; 14.01.2013
comment
Определено е ОК, просто трябва да сте последователни. Трябва да измислите набор от правила и да се придържате към тях. Не е нужно да определяте тези правила предварително, но с натрупания опит ще дойдете със собствените си най-добри практики. Само не забравяйте да сте последователни. - person Bassam Mehanni; 14.01.2013
comment
Това ми беше ясно като звънец. Ще използвам слоя на услугата, както съм виждал преди, за да бъда проводник за слоя хранилище и домейн, поддържайки го тънък. Моят модел на домейн ще остане стабилен както с данни, така и с поведение, тъй като всъщност се чувствам най-удобно с: martinfowler.com/ bliki/AnemicDomainModel.html Благодаря ви за помощта! - person atconway; 15.01.2013

Не непременно най-добрият начин, но ето как обикновено го правя:

  • IService (бизнес логика във вашия случай) се инжектира в контролера (а не в IRepository)
  • Ако ModelState е валиден => контролерът ще извика методи в IService, които приемат модела като параметър(и)
  • IRepository се инжектира в екземпляра на услугата, ако е необходимо.

Това ми позволява да: - Мога да тествам контролери, предоставящи макети на IService. - Дръжте контролера в неведение за хранилището и слоя за достъп до данни.

person qbantek    schedule 14.01.2013