Как указать известный тип WCF в конфигурации, который является универсальным?

StackOverflow https://stackoverflow.com/questions/976811

Вопрос

У меня есть типаж, давайте назовем это 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*/ }

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

<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>

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

Но я собираюсь добавить третий тип, и мне не нравится иметь ненужные, пустые .СЕТЕВЫЕ классы 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 поскольку это не в моем вкусе.Конфигурация, кажется, единственный способ.)

Редактировать

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

Введите 'MyAssembly.Данные `1[System.Int64]' не могут быть добавлены в список известных типов, поскольку другой тип 'MyAssembly.Данные `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}")]
Это было полезно?

Решение

Универсальный тип может быть создан из строки, если строка следует этому шаблону:Имя класса, за которым следует символ "`", за которым следует количество параметров типа (в данном случае это 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"/>

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

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

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

Еще здесь.Взгляните на раздел "Настройка имен контрактов данных для универсальных типов" ниже по странице.

Другие советы

От здесь...

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

<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>

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

<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>

Обратите внимание на элемент use config “параметр” с атрибутами ‘тип’ и ‘индекс’.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top