【问题标题】:How to specify a WCF known type in config that is generic?如何在配置中指定通用的 WCF 已知类型?
【发布时间】:2009-06-10 16:44:25
【问题描述】:

我有一个类型,我们称之为Data<TKey>。我还有一个 WCF 服务合同,它接受一个类型为 Wrapper 的类型(我们称之为 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]”具有相同的数据合同名称“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}")]

【问题讨论】:

  • 是的,我知道! :) 我编辑了我的答案

标签: .net wcf generics known-types


【解决方案1】:

如果字符串遵循以下模式,则泛型类型可以从字符串中实例化: 类名后跟一个“`”字符,后跟类型参数的个数(在本例中为 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”。

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

【讨论】:

  • 谢谢巴雷塔。一旦我用 name 属性解决了问题(请参阅我的编辑),这个简洁的答案非常有效。
  • 感谢您的编辑。这是一个很好的答案,如果我可以投票两次,我会:)
  • 一个小提示,当沿着这条路走时,确保注册的类型是公开的。当我们意识到为什么这个解决方案不能“开箱即用”时,这无疑是一个面对面的时刻
【解决方案2】:

来自here...

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

<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。配置允许 已知类型的定义 任意复杂度。例如,如果 需要定义 Circle>为 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>

注意使用配置元素 具有“类型”属性的“参数” 和“索引”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2019-06-01
    相关资源
    最近更新 更多