Я бы лично рекомендовал сохранить ваше отображение на стороне сервера. Вы, вероятно, проделали большую работу по созданию своего дизайна до того уровня, на котором он сейчас находится; не выбрасывайте это.
Рассмотрим, что такое веб-сервис. Это не просто абстракция над вашим ORM; это контракт . Это публичный API для ваших клиентов, как внутренних, так и внешних.
Публичный API должен иметь мало причин для изменения. Практически любое изменение в API, кроме добавления новых типов и методов, является серьезным изменением. Но ваша модель предметной области не будет такой строгой. Вам придется время от времени менять его по мере добавления новых функций или обнаружения недостатков в оригинальном дизайне. Вы хотите быть в состоянии гарантировать, что изменения в вашей внутренней модели не вызовут каскадные изменения в контракте на обслуживание.
На самом деле это обычная практика (я не буду оскорблять читателей фразой «лучшая практика») по определенной причине создавать конкретные классы Request
и Response
для каждого сообщения; становится намного проще расширять возможности существующих служб и методов, не нарушая их изменений.
Клиенты, вероятно, не хотят точно такую же модель, которую вы используете внутри службы. Если вы являетесь вашим единственным клиентом, то, возможно, это кажется прозрачным, но если у вас есть внешние клиенты и вы видели, насколько часто они могут отличаться от вашей интерпретации вашей системы, тогда вы поймете, как важно не допустить утечки вашей идеальной модели. за пределы сервисного API.
А иногда даже невозможно отправить вашу модель обратно через API. Есть много причин, почему это может произойти:
Циклы в графе объектов. Прекрасно в ООП; катастрофический в сериализации. Вам в конечном итоге приходится делать болезненный постоянный выбор того, в каком «направлении» граф должен быть сериализован. С другой стороны, если вы используете DTO, вы можете сериализовать в любом направлении, в котором хотите, в зависимости от того, какая задача под рукой.
Попытка использовать определенные типы механизмов наследования через SOAP / REST в лучшем случае может быть неудачей. Сериализатор XML старого стиля, по крайней мере, поддерживает xs:choice
; DataContract
нет, и я не буду придираться к обоснованию, но достаточно сказать, что у вас, вероятно, есть некоторый полиморфизм в вашей модели богатых доменов, и его почти невозможно передать через веб-сервис.
Ленивая / отложенная загрузка, которую вы, вероятно, используете, если используете ORM. Достаточно неловко убедиться, что сериализовано правильно - например, с использованием сущностей Linq to SQL, WCF даже не запускает ленивый загрузчик, он просто помещает null
в это поле, если вы не загрузите его вручную - но проблема возникает еще хуже для данных, возвращаемых. Что-то простое, например, авто-свойство List<T>
, которое инициализируется в конструкторе - достаточно часто встречается в модели предметной области - просто не работает в WCF, потому что оно не вызывает ваш конструктор. Вместо этого вам нужно добавить [OnDeserializing]
метод инициализатора, и вы действительно не хотите загромождать модель вашего домена этим мусором.
Я также заметил в скобках, что вы используете NHibernate. Учтите, что такие интерфейсы, как IList<T>
, вообще не могут быть сериализованы через веб-сервис! Если вы используете классы POCO с NHibernate, как и большинство из нас, то это просто не будет работать, точка.
Также может быть много случаев, когда ваша модель внутреннего домена просто не соответствует потребностям клиента, и нет смысла менять модель домена для удовлетворения этих потребностей. Как пример этого, давайте возьмем что-то простое, как счет. Это должно показать:
- Информация об учетной записи (номер счета, имя и т. Д.)
- Данные, относящиеся к счету (номер счета, дата, срок оплаты и т. Д.)
- Информация уровня A / R (предыдущий баланс, просроченные платежи, новый баланс)
- Информация о продукте или услуге для всего, что указано в счете;
- Etc.
Это, вероятно, хорошо вписывается в модель предметной области. Но что, если клиент хочет запустить отчет, который показывает 1200 из этих счетов? Какой-то отчет о сверке?
Это отстой для сериализации. Теперь вы отправляете 1200 счетов с одними и теми же сериализованными данными - одни и те же счета, одни и те же продукты, один и тот же A / R. Внутренне ваше приложение отслеживает все ссылки; он знает, что Счет-фактура № 35 и Счет-фактура № 45 предназначены для одного и того же клиента, и поэтому имеют общую ссылку Customer
; вся эта информация теряется при сериализации, и в итоге вы отправляете смешное количество избыточных данных.
То, что вы действительно хотите, это отправить специальный отчет, который включает в себя:
- Все учетные записи, включенные в отчет, и их A / R;
- Все продукты включены в отчет;
- Все счета-фактуры, только с идентификаторами продуктов и учетных записей.
Вам необходимо выполнить дополнительную «нормализацию» исходящих данных, прежде чем отправлять их клиенту, если вы хотите избежать массовой избыточности. Это сильно способствует подходу DTO; не имеет смысла иметь такую структуру в вашей доменной модели, потому что ваша доменная модель уже по-своему заботится о избыточности.
Я надеюсь, что этих примеров достаточно, чтобы убедить вас сохранить нетронутыми ваши сопоставления из Контракта на обслуживание домена <->. Вы до сих пор делали абсолютно правильные вещи, у вас отличный дизайн, и было бы стыдно отрицать все эти усилия в пользу чего-то, что впоследствии может привести к серьезным головным болям.