N-Tier архитектура с DAL, Repo, Service, API слоеве: с какъв тип обекти всеки слой трябва да се занимава с вход/изход + къде трябва да се извършва валидиране/картографиране?

Мисля, че приложението ми трябва да има поне следните слоеве:

  • DAL (няма общ интерфейс; вземете данните от база данни, вземете данните от друга уеб услуга, вземете данните от файл)
  • Хранилище (CRUD интерфейс за всеки важен/основен агрегат; реализациите варират според източника)
  • Услуга (използва интерфейс на хранилище; реализациите варират според бизнес логиката)
  • Уеб API (услуги за обвиване; контейнер за инсталиране; реализациите варират според параметрите/конфигурацията по време на изпълнение)

Знам, че моят уеб API трябва да връща DTO, който интерпретирам като C# обекти с нищо друго освен автоматично внедрени публични свойства.

На теория понякога ще трябва да направя BigComplicatedServiceCommand, където ще има множество хранилища, участващи в една единица работа, но друг път моят уеб API може също така да извика хранилището директно, защото то просто прави CRUD.

Интересувам се да разбера къде трябва да се извърши картографирането от (въведено в уеб услуга чрез обвързване на уеб api модел) DTO към каквото Услугата изисква - и също така къде трябва да се извърши валидирането.

Грубо казано, имам това в ума си:

В API

  1. Получаване на заявка и карта за маршрут
  2. Използвайте свързващо устройство на модела, за да се свържете с DTO по конвенция
  3. Създайте конкретен контролер с помощта на IoC контейнер
  4. Изпълнете конкретно действие на контролера
  5. В действието на контролера, обвийте слоя на повикване към услуга

Сега, след като стъпка 5 е проблематична. Изпращам ли DTO на сервиза? Тогава моята услуга ще бъде съчетана с моите DTO.

Трябва ли да дефинирам конкретен интерфейс за всеки метод на услуга? Ако е така, те всъщност са техни собствени DTO и бих могъл да дефинирам DTO за пермутация на въвеждане на услуга.

Ако приемем, че моята услуга включва DTO,

  1. В метода на услугата правете бизнес логика и правете повиквания към хранилища
  2. В хранилища, CRUD неща
  3. Връща крайния резултат от метода на услугата към API
  4. Прехвърляне към DTO и връщане от API към Интернет

Сега, трябва ли моите хранилища да се занимават стриктно с обекти на домейн? Ако е така, кой отговаря за кастинга? (Услугата?)

И накрая, имайки предвид валидирането, си мисля:

  • Валидирайте предварително, като използвате едно от следните: ModelStateActionFilter (преди изпълнение на действие), по време на кастинг към всичко, което услугата трябва да приеме като вход. Така че това би гарантирало, че CreateUserService получава обект с Username и Password.
  • Уверете се, че потребителското име е уникално и паролата е достатъчно силна, като използвате хранилища и други услуги
  • Валидирайте на ниво DAL, за да сте сигурни, че Entity Framework е щастлив

Въпросът ми е върху кои (ако има такива) обекти трябва да поставя System.DataAnnotations? Има ли някакъв тип модел в този стек, който трябва да отговаря в която и да е част за собственото си валидиране?

Благодаря за всякаква философска помощ.


person tacos_tacos_tacos    schedule 05.07.2014    source източник
comment
Този въпрос трябва да бъде на programmers.stackexchange.com   -  person Yuval Itzchakov    schedule 05.07.2014


Отговори (1)


Този въпрос ...

Тъй като въпросът ви е дълъг, може да пропусна да обърна внимание на някои точки, но започваме. Между другото, всичко това е "по мое мнение", трябва да промените нещата, както сметнете за добре, за да отговарят по-добре на вашите нужди.

  1. Отървете се от думата "N-Tier". Готините деца в наши дни използват "Onion Architecture".

  2. Започнете с "Основен" проект. Това е мястото, където ще се намират всички ваши основни обекти. Ще имате клиент, поръчка, продукт и т.н. На това ниво не се притеснявайте за базата данни, уеб API или потребителския интерфейс. Вашите обекти трябва да имат методи, свойства и поведение. Всичко НЕ трябва да е Public { get; set; } тук. О, да, не използвайте интерфейси, ако нямате изрична нужда от тях тук.

  3. След вашия "Core" проект можете да се тревожите как да съхранявате тези обекти. Можете да създадете проект "Хранилище / DAL". Вашите хранилища трябва да приемат вашия обобщен корен. Работата е да разберете как да поставите това в базата данни.

  4. Сега проект "Сервиз". Обслужването е лесно. Вашите услуги са отговорни за: Получаване на обект от хранилище, извикване на метод на обект, поставяне на обект обратно в хранилище. Сега вашите услуги могат или да върнат, или да приемат „Core“ обектите, или да изложат своите собствени DTO.

  5. Вашият WEB API / MVC проект ще има вашето взаимодействие с потребителя. Ще се обади на сервиз, за ​​да получи всичко, което поиска. Тук можете да използвате View Models, за да представите на потребителя вместо основните обекти.

-- добре, не е така --

Но ето някои ясни отговори на вашите въпроси:

  1. Web Api никога не трябва да извиква директно хранилището.

  2. Картографирането от всичко, което вашата услуга връща в Web Api DTO/View Model, трябва да се случи в проекта Web Api.

  3. Валидиране: Web Api може да валидира всичко, за да помогне на потребителя. Освен това Core трябва да се валидира добре, основни неща и т.н. ... валидирането ще приключи на много места.

  4. Не дефинирайте интерфейси за всяка услуга. Ако има само една реализация, това вероятно не трябва да е интерфейс.

  5. В метода на услугата вие НЕ правите бизнес логика. Логиката влиза в основните обекти.

  6. Да, хранилища стриктно с Core/Domain обекти. И да, работата на службите да им я даде.

  7. System.DataAnnotations отива в Web Api „Изглед / Модели / DTOs“

person hatcyl    schedule 05.07.2014
comment
Бизнес логиката влиза в основните обекти? какво ще стане, ако данните, върнати на потребителя, са съставни от различни обекти и те трябва да бъдат валидирани заедно. а също и бизнес правилата ще засегнат самия потребителски интерфейс. така че има ли по-добро място за прилагане на бизнес правилата ми? - person Mazen Elkashef; 10.01.2016
comment
@IKashef Ако бизнес правилото определя как трябва да се държи потребителският интерфейс, то изобщо не трябва да бъде бизнес правило. Потребителският интерфейс трябва да бъде представяне на текущото състояние на бизнеса. HTML, бутони, IOS приложения, анимации, ... това са всички начини за представяне на състоянието на бизнеса. - person hatcyl; 10.01.2016
comment
но тези правила са свързани с бизнеса в логиката. например, ако състоянието на продукта е чакащо, тогава може да се редактира или изтрие. ако статус, ако е продаден, трябва да бъде само за четене. това са бизнес правила нали? и не е удобно тези правила да се прилагат само от страната на сървъра. приложението не трябва да показва бутон, който е деактивиран например (бутона за редактиране), той трябва да бъде скрит на първо място. Ако знаете за какво говоря, но все пак смятате, че това не са бизнес правила, можете ли да обясните добра архитектура, която е близка до тази, която предложихте в отговора си? - person Mazen Elkashef; 10.01.2016
comment
@IKashef Очевидно този разговор може да излезе извън контрол много бързо, но ... Да кажем, че вашето бизнес правило е, че ако състоянието на продукта е чакащо, то може да бъде редактирано или изтрито. В този случай вашият продуктов обект може да има свойства, наречени CanDelete и CanEdit. Вътрешно, когато ги прочетете, те ще върнат само true, ако състоянието е pending. Така потребителският интерфейс скрива или показва бутона въз основа само на тези свойства, а не на самото бизнес правило. - person hatcyl; 10.01.2016
comment
Напълно съм съгласен. просто исках отговор във връзка с архитектурата, която предложихте тук. Благодаря ви за подсказката и ако имам още въпроси, просто ще пусна нов. Благодаря ти - person Mazen Elkashef; 11.01.2016