Cómo especificar un tipo conocido WCF en config que es genérico?
-
13-09-2019 - |
Pregunta
Tengo un tipo, vamos a llamarlo Data<TKey>
. También tengo un contrato de servicio WCF que acepta un tipo (permite llamarlo Wrapper
) con una propiedad de tipo Object
(por razones que no voy a entrar, esto no es opcional).
[DataContract]
public class Data<TKey> { ... }
[DataContract]
public class Wrapper
{
[DataMember]
public object DataItem { get; set; }
}
En este momento estoy enviando dos clases IntData
y LongData
:
[DataContract]
public class IntData : Data<int> { /*empty*/ }
[DataContract]
public class LongData : Data<long> { /*empty*/ }
Están configurados tanto en los tipos conocidos fichero de configuración. La configuración se asemeja a algo como esto:
<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>
En este punto, todo funciona bien.
Pero estoy a punto de añadir un tercer tipo y no me gusta tener lo innecesario, vacío y clases IntData
LongData
.NET. Sólo existen porque ...
No sé cómo especificar los tipos genéricos en la configuración de WCF!
Quiero hacer algo como esto, pero no sé la sintaxis exacta.
<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>
¿Cuál es la sintaxis correcta para esto?
(Nota también que no puedo poner los atributos [KnownType(...)]
en Wrapper
ya que no es mi tipo. Config parece ser la única manera.)
Editar
@ respuesta de baretta funcionó muy bien. Sin embargo, nótese que en un principio he recibido este error:
Tipo 'MyAssembly.Data`1 [System.Int64]' no puede ser añadido a la lista de tipos conocidos desde otro tipo 'MyAssembly.Data`1 [System.Int32]' con el mismo nombre de contrato de datos ' http://www.mycompany.com/MyAssembly:Data ' ya está presente.
Yo no lo mencionó en la pregunta original, pero mi tipo tiene un nombre de contrato de datos explícita. Algo como esto:
[DataContract(Name = "Data")]
public class Data<TKey> { ... }
Se ha producido el error anterior hasta Quité el valor de la propiedad Name
del atributo. Esperamos que ayuda a otra persona demasiado. No sé qué formato funciona en este escenario. Estos no lo hizo:
[DataContract(Name = "Data\`1")]
[DataContract(Name = "Data{TKey}")]
Alguien sabe cómo hacer esto?
EDIT 2
Gracias de nuevo a @baretta quien señaló que la sintaxis correcta es, de hecho:
[DataContract(Name = "Data{0}")]
Solución
Un tipo genérico es crear instancias de una cadena, si la cadena sigue este patrón: Nombre de clase seguido de un "`" carácter, seguido por el número de parámetros de tipo (en este caso es 1), seguido de los parámetros de tipo encerrados dentro de "[]", y el uso de una coma como separador parámetro de tipo .
<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>
Editar:. Podría añadir también, que si necesita ser especificado para los parámetros de tipo (althoug que no es el caso para la materia en mscorlib) información de ensamblado, a continuación, anidado "[]" se utiliza
<knownType type="Data`1[[System.Int32, mscorlib]], MyAssembly"/>
Editar:. Usted puede personalizar los nombres de los tipos genéricos de contratos de datos, utilizando el patrón de formato de cadena
[DataContract(Name = "Data{0}")]
public class Data<TKey>
{...}
Por defecto, el nombre generado por el
aquí . Echar un vistazo a la parte de "Personalización de los datos del contrato nombres para tipos genéricos" en la página.
Otros consejos
aquí ...
Conocido tipos también se pueden definir en config como se muestra a continuación.
<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>
La configuración anterior especifica que el parámetro genérico para círculo es el mismo que el parámetro genérico para el Forma tipo declarado. La configuración permite la definición de un tipo conocido de complejidad arbitraria. Por ejemplo, si es necesario definir Círculo
> como el tipo conocido de Forma (por supuesto esto es puramente académico) se puede hacer tan de la siguiente manera.
<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>
Tenga en cuenta el elemento de uso de config “Parámetro” con el ‘tipo’ de los atributos e ‘índice’.