Использование пользовательского DataContractResolver в WCF для переноса деревьев наследования с использованием обобщений - PullRequest
7 голосов
/ 13 марта 2010

У меня есть служба WCF, в которой есть операции, которые принимают не универсальный базовый класс в качестве параметра.

[DataContract]
class Foo
{ ... }

Этот базовый класс, в свою очередь, наследуется такими обобщенными классами, как

[DataContract]
class Bar<T> : Foo
{ ... }

Чтобы это сработало, мне ранее пришлось зарегистрировать KnownTypes для класса Foo, и они должны включать все возможные варианты Bar (например, Bar<string>, Bar<int> и даже Bar<List<string>>).

Однако с помощью DataContractResolver в .NET 4 я смог бы создать средство распознавания, которое правильно хранит (и восстанавливает) классы.

Мои вопросы:

  1. Используются ли DataContractResolvers обычно только на стороне службы, а не клиентом? Если да, то как это будет полезно в этом сценарии?

  2. Неправильно ли я написал DataContractResolver, который сериализует полное имя типа универсального типа, такого как Bar`1[List`1[string, mscorlib], mscorlib]? Не может ли тот же DataContractResolver на стороне клиента восстановить эти типы?

Ответы [ 3 ]

1 голос
/ 25 сентября 2017

Я использовал DataContractResolver раньше; и вот мои выводы:

  1. И клиент, и сервер требуют распознавателя; поскольку сериализация и десериализация происходит с обоих концов. Очевидно, что используется тот же Resolver.
  2. Имена типов являются стандартной частью информации, которую создает DataContractSerializer. Однако это просто тип NAME, а не полное (сборочное) имя

По сути, пользовательский распознаватель позволяет добавить его к клиенту и серверу WCF в качестве поведения:

`foreach (OperationDescription operation in myWCFService.Description.Endpoints[0].Contract.Operations)
    {
      operation.Behaviors.Find<DataContractSerializerOperationBehavior>()
          .DataContractResolver = new MyDataContractResolver();
    }`

Для клиента вы делаете то же самое:

      `foreach (var operation in base.ChannelFactory.Endpoint.Contract.Operations)
  {
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>()
        .DataContractResolver = new MyDataContractResolver();
  }`

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

KnownTypeAttribute (например, используя предоставленный метод для возврата всех известных типов) также можно использовать; но пользовательский распознаватель допускает более гибкий подход, такой как динамическая загрузка типов (например, система плагинов) и создание собственного отображения (Type => имя типа и наоборот)

1 голос
/ 13 марта 2010

Я ожидаю, что это сработает на обоих концах, но я не уверен, что это хорошая идея; он требует дополнительной настройки и не будет работать в Silverlight и т. д. Но он, вероятно, будет работать для «полного» .NET с одинаковыми битами на каждом конце.

0 голосов
/ 19 июля 2011

Не знаю, каков типичный вариант использования DataContractResolver, но согласно этой статье ( MSDN для DataContractResolver ) это должно быть легко выполнено с помощью SharedTypeResolver и совместного использования сборок, которые содержать договор.

Слово предостережения: Поэтому, хотя это кажется возможным, я не совсем уверен, является ли это хорошей идеей с точки зрения дизайна, поскольку это ослабит выразительность контракта. Эти типы будут туннелировать контракт и нарушать совместимость с другими языками программирования, и это приведет к вопросу, является ли использование открытого стандарта, такого как SOAP, правильным решением в первую очередь. DataContract существует для не общих сборок ...

...