如何自定义 WCF XML 序列化

Posted

技术标签:

【中文标题】如何自定义 WCF XML 序列化【英文标题】:How to customize WCF XML serialization 【发布时间】:2010-10-13 14:09:24 【问题描述】:

我们有一个现有的 SOAP Web 服务接口,我们希望使用 WCF 为新应用程序实现该接口。除了一个小细节外,这似乎工作正常。函数返回类型的 XML 命名空间必须不同于 Web 服务本身的 XML 命名空间。而对于我的一生,我无法让它发挥作用。

我用一个小示例项目重现了同样的问题。 WCF 接口:

[XmlSerializerFormat]
[ServiceContract(Namespace = "urn:outer-namespace")]
public interface IService1

    [OperationContract]
    MyClass DoStuff(int value);


[Serializable]
public class MyClass

    [XmlElement(ElementName = "DataString")]
    public string MyString  get; set; 

网络服务实现:

    public class Service1 : IService1

    public MyClass DoStuff(int value)
    
        return new MyClass  MyString = "Wooh!" ;
    

来自该网络服务的响应随后被序列化为: (省略 SOAP 的东西)

  <DoStuffResponse xmlns="urn:outer-namespace">
     <DoStuffResult>
        <DataString>Wooh!</DataString>
     </DoStuffResult>
  </DoStuffResponse>

但我们希望 为 xmlns="urn:inner-namespace"。

我尝试在接口函数或 Web 服务函数上添加 [return: XmlElement(...)] ,但没有成功。 MyClass 类定义中的 [XmlType] 或 [XmlRoot] 也不起作用。

有谁知道如何更改作为 WCF Web 服务函数返回值的对象的序列化 XML 命名空间(或元素名称)?

【问题讨论】:

【参考方案1】:

经过几天的搜索和尝试数十种推荐的解决方案;我终于能够让 WCF 停止强制将 Result 附加到 Web 服务方法名称的包装容器名称。诀窍是将以下装饰器属性添加到 Web 服务接口:

[return:MessageParameter(Name = "whatIWantItNamed")]

该属性应直接放置/定位在接口中的[OperationContract] 属性之后(并且就在实际方法存根之前)。

(我还需要为所有ServiceContractOperationContract 属性添加一个XmlSerializerFormat 属性。)

【讨论】:

【参考方案2】:

使用 XML 序列化(或更好的)数据协定定义属性定义命名空间。

例如使用 XML 序列化:

[Serializable, XmlRoot(namespace="http://example.com/eg1")]
public class MyClass 
  [XmlElement(ElementName = "DataString")]
  public string MyString  get; set; 

例如使用数据合约序列化:

[DataContract(Namespace="http://example.com/eg2")]
public class MyClass 
  [DataMember]
  public string MyString  get; set; 


编辑

根据第一条评论,上述方法行不通,因为希望在消息周围的 SOAP 包装器上设置命名空间,而不是在消息本身上。

OperationContractAttribute 不提供对命名空间的控制,我在方法级别看不到任何其他 WCF 属性。

两种可能性:(1)您可以通过放弃抽象级别并使用消息契约来获得足够的控制。 (2) 获取服务当前的WSDL(使用svcutil.exe),手动调整得到你想要的命名空间,然后再次使用svcutil.exe生成代码,看看生成的代码。

【讨论】:

就像我在问题中已经说过的那样,我尝试添加一个 XmlRoot 属性,但它不起作用。它只将命名空间添加到 MyClass 中的字段,而不是 MyClass 本身。 DataContract 也不起作用,我更喜欢 XmlSerializer 因为重命名和顺序并不重要。 我使用了 svcutil,但没有指定序列化程序,它生成了 MessageContract 和 ServiceContract 与 XmlSerializer 的组合。所以它有一个或两个包装器,我仍然可以使用 XML 属性来使其全部工作。

以上是关于如何自定义 WCF XML 序列化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WCF 中使用自定义序列化或反序列化来强制在 datacontact 的每个属性上创建一个新实例?

如何使用 wcf REST 服务获取自定义对象的 json 响应?

具有自定义 WCF 4.5 WebHttpBehavior 的 UriTemplates

从自定义源(非标准 XML)加载 WCF 配置(用于服务器 + 客户端)

WCF - 如何使用 HTTP(S) 上的二进制编码以编程方式创建自定义绑定

如何在 Spring Boot 2 中使用内容协商建立自定义 xml 序列化