none
Контракты данных WCF. Как не дублировать сущности? RRS feed

  • Вопрос

  • Заголовок звучит страшно, но суть более простая:

    Осваивая WCF прочитал что предпочтительнее передавать не специфичные для нет типы, а создавать свои с атрибутами DataContract и DataMember. В итоге я из класса FileSystemInfo делаю класс FileSystemInformation где и передаю необходимую мне часть данных.

    В итоге при создании ссылки на службу в клиенте создается класс FileSystemInformation с полями аналогичными помеченным DataMember в службе. Но тем не менее это другой класс и ряд полезных свойств (я их не помечал DataMember) в которых нет необходимости при передаче но они необходимы уже на конечной точке в клиенте. К примеру я передаю полный путь к файлу, а на клиенте хочу иметь свойства возвращающие только имя или только расширение.

    И вот тут сложности (и мои попытки решения):

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

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

    - еще один класс FileSystemInformationXXX с конструктором на основе созданного FileSystemInformation созданого мастером, но тогда этот авриант почти аналогичен 2.

    Но ведь базовые классы .Net не переопределяются при создании ссылки!

    Как создать класс единожды с помеченными необходимымы для перечачи свойствами DataMember, а остальными рабочими и объявить его и на хосте и на клиенте, а не дублировать ручками?

Ответы

  • Вынесите partial часть классов в отдельную dll. Подключите эту dll на клиенте и на сервере. Код в одном месте, изменения сразу отображаются и там и там.

    • Предложено в качестве ответа PashaPashModerator 17 мая 2012 г. 12:49
    • Отменено предложение в качестве ответа PhantomSL 18 мая 2012 г. 8:28
    • Помечено в качестве ответа Abolmasov Dmitry 29 мая 2012 г. 9:45
    Отвечающий
  • А чем вас не устроило решение "вынести передаваемые классы в отдельную dll"? Не "добавить их код к клиенту", а просто объявить классы в отдельной dll, и добавить на нее референс и на сервере и на клиенте? По сети будет проходить только то, что помечено аттрибутами, но и на сервере, и на клиенте вы получите объекты абсолютно одинакового типа. С одинаковыми свойствами и методами.

    Именно так и сделано для "базовых классов" .NET - они объявлены в отдельных dll, ссылка на которые есть и на сервере, и на клиенте.


    Модератор
  • В мастере есть кнопка advanced. в advanced диалоге есть пункт Reuse types from referenced assemblies. Там по умолчанию выбрано "... in all referenced assemblies", но иногда подглючивает. Поставьте "...in specified..." и явно выберите свою dll.
    • Помечено в качестве ответа PhantomSL 21 мая 2012 г. 14:20
    Модератор

Все ответы

  • Вынесите partial часть классов в отдельную dll. Подключите эту dll на клиенте и на сервере. Код в одном месте, изменения сразу отображаются и там и там.

    • Предложено в качестве ответа PashaPashModerator 17 мая 2012 г. 12:49
    • Отменено предложение в качестве ответа PhantomSL 18 мая 2012 г. 8:28
    • Помечено в качестве ответа Abolmasov Dmitry 29 мая 2012 г. 9:45
    Отвечающий
  • Что-тоя не совсем понял разве можно загнать в скомпилированный модуль часть объявления класса??? И присоединять (partial) ету часть, то к одному, то к другому? Кажись dll будет воспиринимать этот клас как единый?

    И все же как это делается для базовых класов .Net?

  • Что-тоя не совсем понял разве можно загнать в скомпилированный модуль часть объявления класса??? И присоединять (partial) ету часть, то к одному, то к другому? Кажись dll будет воспиринимать этот клас как единый?

    И все же как это делается для базовых класов .Net?

    Как для базовых не скажу, но если с отдельной dll не прокатывает, то расказываю про грязный хак. Включаете файл c частью класса (не WCF) в один проект. А во второй, добавляете этот же файл не как файл, а как ссылку:

    файл по прежнему один, но в двух проектах...

    Отвечающий
  • Нашел http://msdn.microsoft.com/ru-ru/library/wa80x488.aspx "Разделяемые определения не могут находиться в разных модулях", а модератор уже пометил как ответ...

    • Предложено в качестве ответа YatajgaModerator 18 мая 2012 г. 8:34
    • Отменено предложение в качестве ответа PhantomSL 18 мая 2012 г. 9:22
  • Нашел http://msdn.microsoft.com/ru-ru/library/wa80x488.aspx "Разделяемые определения не могут находиться в разных модулях", а модератор уже пометил как ответ...

    Тут написано почему один из вариантов решений не верен!

    Как это может быть ответом?

  • А клиентская, часть у Вас что за приложение, Silverlight или полноценное .Net?
    Модератор
  • А клиентская, часть у Вас что за приложение, Silverlight или полноценное .Net?

     .Net WinForms
  • Заголовок звучит страшно, но суть более простая:

    Осваивая WCF прочитал что предпочтительнее передавать не специфичные для нет типы, а создавать свои с атрибутами DataContract и DataMember. В итоге я из класса FileSystemInfo делаю класс FileSystemInformation где и передаю необходимую мне часть данных.

    В итоге при создании ссылки на службу в клиенте создается класс FileSystemInformation с полями аналогичными помеченным DataMember в службе. Но тем не менее это другой класс и ряд полезных свойств (я их не помечал DataMember) в которых нет необходимости при передаче но они необходимы уже на конечной точке в клиенте. К примеру я передаю полный путь к файлу, а на клиенте хочу иметь свойства возвращающие только имя или только расширение.

    И вот тут сложности (и мои попытки решения):

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

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

    - еще один класс FileSystemInformationXXX с конструктором на основе созданного FileSystemInformation созданого мастером, но тогда этот авриант почти аналогичен 2.

    Но ведь базовые классы .Net не переопределяются при создании ссылки!

    Как создать класс единожды с помеченными необходимымы для перечачи свойствами DataMember, а остальными рабочими и объявить его и на хосте и на клиенте, а не дублировать ручками?

    По моему,у вас сложилось неправильное представление о WCF и контрактах данных:

    1. "предпочтительнее передавать не специфичные для нет типы, а создавать свои с атрибутами DataContract и DataMember."

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

    2.  "В итоге при создании ссылки на службу в клиенте создается класс FileSystemInformation с полями аналогичными помеченным DataMember в службе. Но тем не менее это другой класс и ряд полезных свойств (я их не помечал DataMember) в которых нет необходимости при передаче но они необходимы уже на конечной точке в клиенте."

    Ессесвенно! Контракт данных нужен только для коммуникации клиента и сервера. Не нужно путать классы контракта данных и бизнес классы.   

    3. Ну и наконец ответ на вопрос: "Как не дублировать сущности?"

    А они и не дублируются: от классов контракта данных и сгенерированного proxy вы никуда не уйдете - в этом и есть WCF. В качестве альтернативы

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

    4. Есть ещё один вариант, но я за него ручаюсь, просто он мне только что пришел в голову: можно после генерации proxy в сгенерированные классы руками дописать все недостающие свойства. По идее, свойства не помеченные никакими атрибутами не должны повлиять на работу.  


    • Изменено A.G.Sedov 21 мая 2012 г. 12:20
  • Ваша идея под пунктом 4, мной и используется (см. вопрос пункт 2).

    И возможно я бы не задавал вопрос если бы не тот факт что передаваемые через WCF базовые классы являются по вашей терминологии: и классами контракта данных и бизнес классами. А вот этот пункт меня и гложет:)

    Хочу знать как можно описать класс единожды возможно это будет действительно dll, но подключить ее и на хосте и на клиенте. Объект проходя через среду WCF (сериализация - передача - десериализация) будет восстановлен на конце в исходном виде.

  • А так, на сколько я понял, обязательно нужен объект посредник (класс контракта данных), а на концах два почти эдентичных класса (методы и свойства дублируются "ручками"). Различие только:

    • Класс на хосте может быть использован в конструкторе объекта контракта данных
    • Класс на клиенте имеет конструктор на основе объекта прокси (отражение объекта контракта данных).

    Неужели нет дргого пути...

  • А чем вас не устроило решение "вынести передаваемые классы в отдельную dll"? Не "добавить их код к клиенту", а просто объявить классы в отдельной dll, и добавить на нее референс и на сервере и на клиенте? По сети будет проходить только то, что помечено аттрибутами, но и на сервере, и на клиенте вы получите объекты абсолютно одинакового типа. С одинаковыми свойствами и методами.

    Именно так и сделано для "базовых классов" .NET - они объявлены в отдельных dll, ссылка на которые есть и на сервере, и на клиенте.


    Модератор
  • А чем вас не устроило решение "вынести передаваемые классы в отдельную dll"? Не "добавить их код к клиенту", а просто объявить классы в отдельной dll, и добавить на нее референс и на сервере и на клиенте? По сети будет проходить только то, что помечено аттрибутами, но и на сервере, и на клиенте вы получите объекты абсолютно одинакового типа. С одинаковыми свойствами и методами.

    Именно так и сделано для "базовых классов" .NET - они объявлены в отдельных dll, ссылка на которые есть и на сервере, и на клиенте.


    При созданиии прокси класса мастер ам создает класс и именем аналогичным классу (контракта данных) хоста. А потом начинает ругаться о совпадении имен при копиляции... (между классом созданным мастером и нашим его определением).

    Вернее он не ругается из-за различных пространств имен, но это два различных класса никак не связанных между собой.

    Возможно я что-то не так делал, вы проверяли свой вариант?

  • В мастере есть кнопка advanced. в advanced диалоге есть пункт Reuse types from referenced assemblies. Там по умолчанию выбрано "... in all referenced assemblies", но иногда подглючивает. Поставьте "...in specified..." и явно выберите свою dll.
    • Помечено в качестве ответа PhantomSL 21 мая 2012 г. 14:20
    Модератор
  • Не знаю то ли я попал на пример плохого обучения по книжке где рассматривается детский пример и передаются string да int, то ли заглючил мастер, то ли я оказался крайне невнимателен.

    Но именно ваш (PashaPash) подход верен, а я искал решения не в том направлении. А ведь веь прикол в том что при создании хоста сразу создается dll с контрактом, а потом она хостится отдельным приложением. Так что все необходимое уже присутствует, только стоит добавить ссылку на другой проект одного и тогоже решения...

    У меня сейчас многое еще не сработало, но действительно это верный подход и так передаются базовые классы .net

    Спасибо всем откликнувшимся