Как указать WCF известный тип в конфигурации, который является общим? - PullRequest
8 голосов
/ 10 июня 2009

У меня есть тип, назовем его Data<TKey>. У меня также есть контракт на обслуживание WCF, который принимает тип (давайте назовем его Wrapper) со свойством типа Object (по причинам, которые я не буду обсуждать, это не является обязательным).

[DataContract]
public class Data<TKey> { ... }

[DataContract]
public class Wrapper
{
    [DataMember]
    public object DataItem { get; set; }
}

Прямо сейчас я отправляю два класса IntData и LongData:

[DataContract]
public class IntData : Data<int> { /*empty*/ }

[DataContract]
public class LongData : Data<long> { /*empty*/ }

Они оба настроены в файле конфигурации известных типов. Конфиг напоминает что-то вроде этого:

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <knownType type="IntData, MyAssembly"/>
          <knownType type="LongData, MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

На данный момент все работает нормально.

Но я собираюсь добавить третий тип, и мне не нравится иметь ненужные, пустые классы .NET IntData и LongData. Они существуют только потому, что ...

Я не знаю, как указать универсальные типы в конфигурации WCF!

Я хочу сделать что-то подобное, но не знаю точного синтаксиса.

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <!-- this syntax is wrong -->
          <knownType type="Data{System.Int32}, MyAssembly"/>
          <knownType type="Data{System.Int64}, MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Какой правильный синтаксис для этого?

(Обратите внимание, что я не могу поставить [KnownType(...)] атрибуты на Wrapper, так как это не мой тип. Кажется, что единственный способ - это Config.)

EDIT

@ Ответ baretta сработал хорошо. Обратите внимание, что изначально я получил эту ошибку:

Тип «MyAssembly.Data`1 [System.Int64]» нельзя добавить в список известных типов, поскольку другой тип «MyAssembly.Data`1 [System.Int32]» с тем же именем контракта данных «http://www.mycompany.com/MyAssembly:Data' уже присутствует.

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

[DataContract(Name = "Data")]
public class Data<TKey> { ... }

Вышеуказанная ошибка происходила до тех пор, пока я не удалил значение свойства Name из атрибута. Надеюсь, что это поможет кому-то еще. Я не знаю, какой формат работает в этом сценарии. Это не:

[DataContract(Name = "Data\`1")]
[DataContract(Name = "Data{TKey}")]

Кто-нибудь знает, как это сделать?

РЕДАКТИРОВАТЬ 2

Еще раз спасибо @baretta, который указал, что на самом деле правильный синтаксис:

[DataContract(Name = "Data{0}")]

Ответы [ 2 ]

18 голосов
/ 10 июня 2009

Универсальный тип является экземпляром из строки, если строка следует этому шаблону: Имя класса, за которым следует символ "` ", затем число параметров типа (в данном случае это 1), за которыми следуют параметры типа, заключенные в" [] ", и использование запятой в качестве разделителя параметров типа .

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <!-- this syntax is all good -->
          <knownType type="Data`1[System.Int32], MyAssembly"/>
          <knownType type="Data`1[System.Int64], MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Редактировать: Я также мог бы добавить, что если для параметров типа необходимо указать информацию о сборке (хотя это не относится к вещам в mscorlib), то используется вложенный "[]".

<knownType type="Data`1[[System.Int32, mscorlib]], MyAssembly"/>

Редактировать: Вы можете настроить имена универсальных типов в контрактах данных, используя шаблон формата строки.

[DataContract(Name = "Data{0}")]
public class Data<TKey>
{...}

По умолчанию имя, сгенерированное для типа Data , выглядит примерно так: «DataOfInt32HJ67AK7Y», где «HJ67AK7Y» хеш, сгенерированный из строки «urn: default» или пространства имен вашего класса, если оно есть. Но «Data {0}» даст ему имя «DataInt32».

Подробнее здесь . Ознакомьтесь с разделом «Настройка имен контрактов данных для универсальных типов» вниз по странице.

5 голосов
/ 10 июня 2009

С здесь ...

Известный типы также могут быть определены в конфигурации как показано ниже.

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
         <add type="MyCompany.Library.Shape`1,
              MyAssembly, Version=2.0.0.0, Culture=neutral,
              PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
            <knownType type="MyCompany.Library.Circle`1,
                       MyAssembly, Version=2.0.0.0, Culture=neutral,
                       PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
                    <parameter index="0"/>
            </knownType>
         </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

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

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
         <add type="MyCompany.Library.Shape`1,
              MyAssembly, Version=2.0.0.0, Culture=neutral,
              PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
            <knownType type="MyCompany.Library.Circle`1,
                       MyAssembly, Version=2.0.0.0, Culture=neutral,
                       PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
                   <parameter type="System.Collections.Generic.Dictionary`2">
                      <parameter type="System.String"/>
                      <parameter index="0"/>
                   </parameter>                
            </knownType>
         </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Обратите внимание на использование элемента конфигурации «Параметр» с атрибутами «тип» и "индекс".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...