«Не используйте абстрактный базовый class в Design; но в моделировании / анализе “

Я новичок в SOA, хотя у меня есть некоторый опыт работы в OOAD.

Одним из руководящих принципов проектирования SOA является использование только абстрактных classов для моделирования. Опустите их из проекта ». Использование абстракции может быть полезным при моделировании (этап анализа).

На этапе анализа я придумал базовый class BankAccount. Специализированные classы, полученные из него, это «FixedAccount» и «SavingsAccount». Мне нужно создать службу, которая вернет все учетные записи (список учетных записей) для пользователя. Какова должна быть структура службы (ов) для удовлетворения этого требования?

Примечание. Было бы замечательно, если бы вы могли продемонстрировать код с помощью WCF .

Похоже, вы пытаетесь использовать SOA для удаленного доступа к вашей объектной модели. Вам лучше взглянуть на взаимодействия и возможности, которые вы хотите, чтобы ваш сервис отображался, и избегать раскрытия сведений о наследовании реализации ваших сервисов.

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

[ServiceContract] interface ISomeService { [OperationContract] Collection ListAccountsForUser( User user /*This information could be out of band in a claim*/); } [DataContract] class AccountSummary { [DataMember] public string AccountNumber {get;set;} [DataMember] public string AccountType {get;set;} //Other account summary information } 

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

Обновление :

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

Я бы не советовал разоблачить ваш OOAD через DTO в отдельном слое, что обычно приводит к раздутому интерфейсу, в котором вы передаете много данных, которые не используются, и религиозно отображать их в и из того, что по существу является копией вашей модели домена с удаленной логикой, и я просто не вижу значения. Обычно я создаю свой сервисный уровень вокруг операций, которые он предоставляет, и я использую DTO для определения взаимодействия службы.

Использование DTO на основе открытых операций, а не модели домена, помогает поддерживать инкапсуляцию службы и уменьшает связь с моделью домена. Не подвергая воздействию моей модели домена, мне не нужно компрометировать видимость или наследование поля ради сериализации.

например, если бы я подвергал метод переноса из одной учетной записи в другую, интерфейс службы выглядел бы примерно так:

 [ServiceContract] interface ISomeService { [OperationContract] TransferResult Transfer(TransferRequest request); } [DataContract] class TransferRequest { [DataMember] public string FromAccountNumber {get;set;} [DataMember] public string ToAccountNumber {get;set;} [DataMember] public Money Amount {get;set;} } class SomeService : ISomeService { TransferResult Transfer(TransferRequest request) { //Check parameters...omitted for clarity var from = repository.Load(request.FromAccountNumber); //Assert that the caller is authorised to request transfer on this account var to = repository.Load(request.ToAccountNumber); from.Transfer(to, request.Amount); //Build an appropriate response (or fault) } } 

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

 [ServiceContract] interface ISomeService { [OperationContract] TransferResult Transfer(AccountDto from, AccountDto to, MoneyDto dto); } 

и AccountDto – это копия полей в учетной записи, как потребитель, какие поля следует заполнять? Все они? Если для поддержки новой операции добавлено новое свойство, теперь все пользователи всех операций могут видеть это свойство. WCF позволяет мне отмечать это свойство как необязательное, чтобы я не разбивал всех своих других клиентов, но если это необходимо для новой операции, клиент только узнает, когда они вызовут операцию.

Хуже того, как исполнитель службы, что произойдет, если они предоставят мне текущий баланс? Должен ли я доверять этому?

Общее правило заключается в том, чтобы спросить, кто владеет данными, клиентом или службой? Если клиент владеет им, он может передать его службе и после выполнения некоторых основных проверок услуга может ее использовать. Если услуга принадлежит ей, клиент должен только передать достаточно информации для службы, чтобы получить то, что ей нужно. Это позволяет службе поддерживать согласованность данных, которыми она владеет.

В этом примере службе принадлежит информация об учетной записи, а ключ для поиска – номер учетной записи. Хотя услуга может подтвердить сумму (положительная, поддерживаемая валюта и т. Д.), Это принадлежит клиенту, и поэтому мы ожидаем, что все поля в DTO будут заполнены.

Таким образом, я видел, как это было сделано всеми тремя способами, но разработка DTO вокруг конкретных операций была, безусловно, наиболее успешной как из сервисов, так и из потребительских реализаций. Он позволяет операциям развиваться самостоятельно и очень четко о том, что ожидается службой и что будет возвращено клиенту.

Я считаю, что лучшая практика здесь заключается в том, чтобы не использовать наследование в ваших данных-контрактах:

 [DataContract] class SavingsAccount { public string AccountNr { ... } .... } [DataContract] class FixedAccount { public string AccountNr { ... } .... } 

Это работает для большинства сценариев, но не для получения списка смешанных учетных записей.
Если это действительно важно, подумайте:

 [DataContract] class AccountDTO { public string AccountType { ... } public string AccountNr { ... } .... } 

который по сути является ответом @ jageall.

Я бы очень позаимствовал то, что говорили здесь другие, но, вероятно, нужно добавить их:

  • Большинство SOA-систем используют Web-сервисы для связи. Веб-службы выставляют свой интерфейс через WSDL. WSDL не имеет никакого представления о наследовании.
  • Все поведение в ваших DTO будет потеряно, когда они пересекут провод
  • Все частные / защищенные поля будут потеряны, когда они пересекут провод

Представьте себе этот сценарий (случай глупый, но иллюстративный):

 public abstract class BankAccount { private DateTime _creationDate = DateTime.Now; public DateTime CreationDate { get { return _creationDate; } set { _creationDate = value; } } public virtual string CreationDateUniversal { get { return _creationDate.ToUniversalTime().ToString(); } } } public class SavingAccount : BankAccount { public override string CreationDateUniversal { get { return base.CreationDateUniversal + " UTC"; } } } 

Теперь вы используете «Добавить ссылку на службу» или «Добавить веб-ссылку» на своем клиенте (а не повторно использовать сборки) для доступа к сберегательной учетной записи.

 SavingAccount account = serviceProxy.GetSavingAccountById(id); account.CreationDate = DateTime.Now; var creationDateUniversal = account.CreationDateUniversal; // out of sync!! 

То, что произойдет, это изменения в CreationDate которые не будут возвращаться к CreationDateUniversal так как нет реализации, пересекающей провод, а только значение CreationDateUniversal во время сериализации на сервере .

  • Конфигурация клиента для использования веб-службы WCF JSON
  • Возврат сервиса WCF «Метод не разрешен»
  • Удалите объект JSON, отправленный из приложения Android в веб-службу WCF
  • Как я могу исправить проблему с двойным хопом Kerberos?
  • Как я могу игнорировать свойство при сериализации с помощью DataContractSerializer?
  • Почему WCF возвращает myObject вместо List , как я ожидал?
  • Любой способ заставить DataContractJsonSerializer правильно сериализовать словари?
  • Динамическое изменение URL-адреса URL-адреса веб-службы WCF через файл конфигурации
  • Большой запрос веб-службы WCF с ошибкой (400) Ошибка HTTP-запроса
  • Как настроить программные типы WCF?
  • Передача сложных объектов в службу restа WCF
  • Давайте будем гением компьютера.