如何在同一主机上同时支持DataContractSerializer和XMLSerializer?

时间:2010-06-11 19:50:31

标签: c# .net wcf xml-serialization datacontractserializer

在我们的生产环境中,我们的WCF服务使用XMLSerializer进行序列化。为此,我们的服务接口具有[XMLSerializerFormat]属性。现在,我们需要更改为DataContractSerializer,但我们必须与现有客户端保持兼容。因此,我们必须使用两个序列化程序公开每个服务。

我们有一个约束:我们不想重新定义每个合约接口两次,我们有50个服务合约接口,我们不想拥有

IIncidentServiceXml 
IIncidentServiceDCS
IEmployeeServiceXml 
IEmployeeServiceDCS
IContractServiceXml 
IContractServiceDCS

我们怎么能这样做?


更多信息

这是对我们迄今为止所尝试的内容的描述,但我愿意尝试完全不同的方法:

我们尝试通过自己的ServiceHostFactory类中的代码创建所有端点。基本上我们创建两个端点两次。问题是在运行时,WCF抱怨该服务有两个具有相同联系人名称但具有不同ContractDescription实例的端点。消息说我们应该使用不同的合同名称或重用相同的ContractDescription实例。

其他尝试:

我们还尝试通过为每个ContractDescription实例使用不同的命名空间来完成此操作。这样我们将保持相同的合同接口(IIncidentService),但有两个不同的命名空间:

http://ourcompany/XML/IIncidentService
http://ourcompany/DCS/IIncidentService

有了这个,我们能够走得更远,但服务崩溃了一个奇怪的例外:

An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension: System.ServiceModel.Description.XmlSerializerOperationBehavior
contract: http://ourcompany.cs/XML:IUserServiceWCF ----> System.NullReferenceException: Object reference not set to an instance of an object.
   at System.ServiceModel.Description.XmlSerializerMessageContractExporter.ExportFaults(Object state)
   at System.ServiceModel.Description.MessageContractExporter.ExportMessageContract()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.System.ServiceModel.Description.IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext contractContext)
   at System.ServiceModel.Description.WsdlExporter.CallExtension(WsdlContractConversionContext contractContext, IWsdlExportExtension extension)

3 个答案:

答案 0 :(得分:1)

简短的回答是,你不能,正是因为你的错误信息所说的原因,你不能拥有与你有效的同名的太多端点。我认为你必须做你所说的你不想做的事。

This might be your only option

  

问题是要指定一个   服务是使用XmlSerializer   你需要申报   [XmlSerializerFormat]属性   服务或合同。那以后   我们想对两者使用相同的   端点我们不能把它放在那里,所以   我们留下了它   合同。然而,当它归结为   对它来说,两个端点都在使用   相同的服务和代理相同   合同对吗?

     

嗯,不一定是这样。您   可以得到合同A.   合同B,然后有服务   实施合同A   两份合同中的一切都是一部分   的服务。对于这个例子   但是,合同B将是我们的   标准合同和合同A将   是一个只定义的界面   [XmlSerializerFormat]属性。

但是我不能保证你会在不做任何改动的情况下使用你现有的客户代码。

答案 1 :(得分:1)

使用[DataContract]和[DataMember]标签创建对象。 XmlSerializer和DataContractSerializer都会很好地序列化对象。他们更新了3.0框架中的XmlSerializer来处理数据提取序列化。 DataContractSerializer可以处理[Serializable]对象,但行为不精确,需要一些调整。

使用数据合约制作所有对象。这样您就不必担心进行两次调用(每次调用一次)。您可以使用XmlSerializer或DataContractSerializer,没有任何问题。

如果您需要添加行为属性,您可以随时添加[Serializable]和[DataContract]。

[Serializable]
[DataContract]
public class Customer

{
    [DataMember]
    public int Age { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public int Number { get; set; }

    [DataMember]
    public string FullName { get; set; }

    [XmlIgnore]
    public int IgnoredNumber { get; set; }
}

XmlSerializer序列化为:

<?xml version="1.0" encoding="utf-16" ?> 
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Age>88</Age> 
  <Name>Bob</Name> 
  <Number>808</Number> 
  <FullName>Bob Jones</FullName> 
  </Customer>

DataContractSerializer序列化为:

  <?xml version="1.0" encoding="utf-8" ?> 
<Customer xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
  <Age>88</Age> 
  <FullName>Bob Jones</FullName> 
  <Name>Bob</Name> 
  <Number>808</Number> 
  </Customer>

你可以显然强制命名空间,以便它们完全匹配。这只是为了举例。

答案 2 :(得分:0)

如果有两个服务实现相同的合同呢?

像:

class DcsService : Service
{}

[XmlSerializerFormat] 
class XmlService : Service
{}

class Service : IServiceContract
{}

从未使用XmlSerializer,但我们将此构造用于其他目的。