Контрактный дизайн данных WCF с внедрением зависимостей - PullRequest
1 голос
/ 11 марта 2011

Итак, у меня есть многоуровневое приложение, к которому я добавляю интерфейс службы WCF. Сервис - это просто фасад со всей нашей бизнес-логикой, уже существующей в Business Objects (BO) на уровне Business Logic Layer (BLL), который является библиотекой классов. Внутри BLL мы используем инжектор конструктора для внедрения зависимостей в BO. Все это работает с хорошим модульным тестированием и т. Д. К проблеме ...

Обычно я просто создавал бы набор объектов запросов / ответов в виде DataContracts для каждого метода службы с соответствующими свойствами для операции. Если бы операция требовала, чтобы одна из наших «сущностей» была передана в метод или из метода, я бы просто определил свойство этого типа, и все было бы хорошо (все наши BO сериализуемы). Однако когда одна из этих «сущностей» передается в метод службы, WCF десериализует объект, даже не вызывая конструкторы, которые мы определили, и, как следствие, зависимости не разрешаются.

Давайте использовать случай с сервисным методом, который называется CreateSomething . Обычно я определяю это как служебную операцию с такой подписью:

CreateSomethingResponse CreateSomething(CreateSomethingRequest request);

CreateSomethingRequest будет DataContract и будет иметь среди своих свойств свойство типа Something , представляющее «сущность», передаваемую в службу. Что-то , в данном случае, это бизнес-объект, который ожидает получения экземпляра интерфейса ISomethingRepository из контейнера DI при создании экземпляра, что, как я уже говорил выше, не происходит, когда WCF десериализует объект на сервере.

Опция # 2 - удалить свойство Something из DataContract и определить каждое из свойств явно в моем DataContract, а затем в моем методе обслуживания создать новый экземпляр Something класс, позволяя контейнеру внедрить зависимость, а затем отобразить значения свойств из объекта DataContract в BO. И я, конечно, могу это сделать, но меня беспокоит наличие двух мест для внесения изменений, если, скажем, я хочу добавить свойство к типу Something . И с большим количеством свойств, много дублирования кода.

Кто-нибудь переходил этот мост и, если да, можете ли вы поделиться своими мыслями и тем, как вы подходите или подходите к этой ситуации в ваших собственных приложениях? Thx !!!

Ответы [ 2 ]

2 голосов
/ 11 марта 2011

На вашу проблему есть два ответа:

Во-первых: не отправляйте свои объекты и не используйте вместо них объекты передачи данных. Ваши объекты - это бизнес-объекты со своей логикой и данными. Логика бизнес-объектов, скорее всего, используется для управления данными. Поэтому пусть бизнес-объект контролирует свои данные на бизнес-уровне и обменивается только фиктивными ящиками.

Второе: если вы не хотите следовать первому подходу, проверьте документацию вашего контейнера IoC. Есть обычно два метода для разрешения зависимостей. Например, Unity предлагает:

  • Resolve - создает новый экземпляр и внедряет все зависимости (необходимые для внедрения в конструктор)
  • BuildUp - принимает существующий экземпляр и разрешает все зависимости свойств. Это должен быть ваш выбор.
0 голосов
/ 15 марта 2011

Спасибо, Ладислав, за ваш ответ, поскольку вы подтвердили то, что уже было в моей голове.

В итоге я немного изменил свой подход. Я понял, что мое использование бизнес-объекта само по себе было излишним и ненужным. Или, может быть, просто неправильно. Оценивая свои требования, я понял, что могу «упростить» свой подход и заставить все работать. Взяв каждый логический слой в моем приложении и посмотрев, какие данные необходимо передать между слоями, я нашел проект, который работает.

Во-первых, для моего уровня бизнес-логики вместо бизнес-объекта я реализовал объект Unit of Work: SomethingManager . SomethingManager привязан к моему корневому объекту Something , поэтому любое действие, которое я хочу выполнить с Something , выполняется с помощью SomethingManager . Это включает в себя такие методы, как GetById, GetAll, Save и Delete.

Класс SomethingManager принимает в своем конструкторе два объекта: IValidator и ISomethingRepository . Они будут введены контейнером IoC. Первый позволяет мне выполнить всю необходимую проверку с использованием любой выбранной нами среды (первоначально блока приложений проверки), а второй дает мне невежество в отношении стойкости и абстрагирует от использования Linq-to-SQL сегодня, а также значительно упрощает обновление до EF4 в дальнейшем.

Для моего уровня обслуживания я подключил контейнер IoC (в данном случае Unity) к WCF, чтобы экземпляр службы создавался контейнером. Это позволяет мне внедрить экземпляр ISomethingManager в мой сервис. Используя интерфейс, я могу сломать зависимость и легко провести модульное тестирование класса обслуживания. Кроме того, поскольку контейнер внедряет экземпляр ISomethingManager , он создает его и автоматически разрешает его зависимости.

Затем я создал DataContracts, чтобы представить, как должны выглядеть данные при передаче по сети через сервис. Каждый объект Запрос / Ответ содержит эти DataContracts как DataMembers вместо прямой ссылки на мои классы сущностей (или BO). Это сервисный метод для отображения данных, поступающих или идущих на уровень бизнес-логики (через ISomethingManager ) - с помощью AutoMapper, чтобы сделать это чистым и эффективным.

Вернувшись на уровень данных, я просто расширил сгенерированные классы сущностей, определив частичный класс, который реализует требуемый интерфейс из BLL. Например, сущность Something L2S имеет частичное определение, которое реализует ISomething . И ISomething - это то, что SomethingManager ISomethingManager интерфейс) и ISomethingRepository работают с тем, чтобы упростить запрос к базе данных и передать Сущность L2S вверх по цепочке для уровня обслуживания, чтобы потреблять и передавать (без уровня обслуживания, имеющего какие-либо знания или зависимость от реализации L2S).

Я ценю любые комментарии, вопросы, критику или предложения, которые есть у кого-либо об этом подходе.

...