如何在配置中指定通用的WCF已知类型?

时间:2009-06-10 16:44:26

标签: .net wcf generics known-types

我有一个类型,我们称之为Data<TKey>。我还有一个WCF服务合同,它接受一个类型为Wrapper的属性(让我们称之为Object)(由于我不会进入的原因,这不是可选的)。

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

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

现在我发送了两个课程IntDataLongData

[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 IntDataLongData。它们只存在是因为......

我不知道如何在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.Data`1 [System.Int64]'无法添加到已知类型列表中,因为另一个类型'MyAssembly.Data`1 [System.Int32]'具有相同的数据协定名称'{{3} }'已经存在。

我没有在原始问题中提及它,但我的类型有明确的数据合约名称。像这样:

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

在我从属性中删除Name属性值之前发生了上述错误。希望能帮助其他人。我不知道在这种情况下哪种格式有效。这些没有:

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

任何人都知道怎么做?

编辑2

再次感谢@baretta,他指出正确的语法实际上是:

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

2 个答案:

答案 0 :(得分:18)

如果字符串遵循此模式,则可以从字符串中实例化泛型类型: 类名后跟一个“`”字符,后跟类型参数的数量(在本例中为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&lt; Int32&gt;生成的名称类型是“DataOfInt32HJ67AK7Y”,其中“HJ67AK7Y” 是字符串“urn:default”生成的哈希,或者类的命名空间(如果有的话)。但是“Data {0}”会将其命名为“DataInt32”。

更多here。请查看页面下方的“为通用类型自定义数据合同名称”部分。

答案 1 :(得分:5)

来自here ...

  

已知   类型也可以在config中定义   如下所示。

<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。配置允许   已知类型的定义   任意复杂性。例如,如果   需要定义   圈&LT;字典&LT; string,T&gt;&gt;作为   已知类型的形状&lt; 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>
  

注意使用config元素   带有'type'属性的“parameter”   和'索引'。