Как указать известный тип WCF в конфигурации, который является универсальным?
-
13-09-2019 - |
Вопрос
У меня есть типаж, давайте назовем это 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 “параметр” с атрибутами ‘тип’ и ‘индекс’.