2017-02-17 26 views
2

我们有一个WCF的设置有以下合约:添加多个命名空间MessageContract WCF响应对象(MessageBodyMember)

[ServiceContract(
    Namespace = Constants.Namespaces.HL7Namespace, 
    Name = Constants.Roles.ContentRequiredDocumentManagementSystem)] 
// XmlSerializerFormat is needed to expose the HL7 schema fields without the "Field" suffix on each one, eg: idField 
[XmlSerializerFormat] 
public interface ICDARequest 
{ 
    [OperationContract(
     // wsdl request action 
     Action = Constants.Namespaces.HL7Namespace + ":" + Constants.Interactions.RCMR_IN000029UV01 + "." + Constants.VersionType.NormativeCode + Constants.Version.InteractionVersion, 
     // wsdl operation name 
     Name = Constants.Interactions.RCMR_IN000029UV01, 
     // wsdl response action 
     ReplyAction = Constants.Namespaces.HL7Namespace + ":" + Constants.Interactions.RCMR_IN000030UV01 + "." + Constants.VersionType.NormativeCode + Constants.Version.InteractionVersion)] 
    SearchMessagesResponse SearchMessages(SearchMessagesRequest RCMR_IN000029UV01); 


    [MessageContract(
     IsWrapped = false] 
    public class SearchMessagesResponse 
    { 
     [MessageBodyMember(
      Name = State.Constants.Interactions.RCMR_IN000030UV01, 
      Namespace = State.Constants.Namespaces.HL7Namespace)] 
     public RCMR_IN000030UV01 data; 
    } 
} 
  • 这些都是基于基于使用xsd.exe的HL7v3模式,它已经生成的类。
  • 然后,我们改变了模式,使用自定义名称空间添加自定义元素,以区分它并重新生成类。
  • 这工作得很好。

它补充说:

​​

这是什么期望。

然后在WCF服务,我们能够使用新的类和成员:

var distStatus = new BCCDXDistributionStatus(); 
distStatus.receivedTime = CreateTS(locStat.MessageDownloadDate); 

这个然后被序列化和送出通过线路看起来像:

<distributionStatus xmlns="urn:bccdx.ca"> 
    <receivedTime value="201702150956-0800"/> 
</distributionStatus> 

这几乎是正确。这个麻烦来自XML文档没有提及"urn:bccdx.ca"命名空间的事实。我假设它会在序列化时自动添加到文档根元素,但我错了。下面是该结束了看起来像:

<RCMR_IN000030UV01 ITSVersion="XML_1.0" xmlns="urn:hl7-org:v3"> 
... 
</RCMR_IN000030UV01> 

时候它真正需要的是一样的东西:

<RCMR_IN000030UV01 ITSVersion="XML_1.0" xmlns="urn:hl7-org:v3" xmlns:x="urn:bccdx.ca"> 
... 
</RCMR_IN000030UV01> 

注意瓮:bccdx.ca前缀

我想知道怎么样,如果可以的话,我们可以通过契约为结果的序列化消息XML添加多个名称空间和前缀?我已经看到了重写默认序列化器的提示,但我宁愿不要。当然这已经被认为和处理过?

+1

1)有什么办法可以将它扩展到[mcve],或者至少是可以编译的东西,而不会丢失类型? 2)你说你使用'xsd.exe'来生成你的类,你在某处应用了'[XmlSerializerFormat]'吗?我没有看到它的问题。 – dbc

+0

谢谢,是的,我编辑添加'XmlSerializerFormat'到原始问题。 – Bensonius

回答

1

首先,我要假设,在你的服务合同,您指定使用的XmlSerializer地方使用[XmlSerializerFormat],比如像这样:

[ServiceContract()] 
[XmlSerializerFormat] 
public interface IService1 
{ 
    [OperationContract(
     // wsdl request action 
     Action = Constants.Namespaces.HL7Namespace + ":" + Constants.Interactions.RCMR_IN000029UV01 + "." + Constants.VersionType.NormativeCode + Constants.Version.InteractionVersion, 
     // wsdl operation name 
     Name = Constants.Interactions.RCMR_IN000029UV01, 
     // wsdl response action 
     ReplyAction = Constants.Namespaces.HL7Namespace + ":" + Constants.Interactions.RCMR_IN000030UV01 + "." + Constants.VersionType.NormativeCode + Constants.Version.InteractionVersion)] 
    SearchMessagesResponse SearchMessages(/* SearchMessagesRequest RCMR_IN000029UV01*/); 
} 

虽然这不是你的问题中提到的,如果你不这样做,那么类型中的[System.Xml.Serialization.XmlElementAttribute(...)]属性声明将不起作用,因为它们被DataContractSerializer忽略。

其次,我会假设你RCMR_IN000030UV01类型目前看起来是这样的:

[XmlRoot(ElementName = "RCMR_IN000030UV01", Namespace = "urn:hl7-org:v3")] 
public partial class RCMR_IN000030UV01 
{ 
    // The initially auto-generated code 
    [XmlAttribute(AttributeName = "ITSVersion")] 
    public string ITSVersion { get; set; } 
} 

public partial class RCMR_IN000030UV01 
{ 
    // The added property 
    [System.Xml.Serialization.XmlElementAttribute("distributionStatus", Namespace = "urn:bccdx.ca", IsNullable = false)] 
    public BCCDXDistributionStatus distStatus { get; set; } 
} 

[System.Xml.Serialization.XmlTypeAttribute(TypeName = "BCCDX.DistributionStatus", Namespace = "urn:bccdx.ca")] 
public partial class BCCDXDistributionStatus 
{ 
    [System.Xml.Serialization.XmlElementAttribute("receivedTime", Namespace = "urn:bccdx.ca", IsNullable = false)] 
    public TS receivedTime { get; set; } 
} 

public class TS 
{ 
    [XmlAttribute("value")] 
    public DateTime Value { get; set; } 
} 

目前您的服务将返回XML,看起来像这样:

<RCMR_IN000030UV01 ITSVersion="1.0" 
    xmlns="urn:hl7-org:v3" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <distributionStatus 
     xmlns="urn:bccdx.ca"> 
     <receivedTime value="2017-02-23T00:00:00-05:00"/> 
    </distributionStatus> 
</RCMR_IN000030UV01> 

但是,你要这个:

<RCMR_IN000030UV01 ITSVersion="1.0" 
    xmlns="urn:hl7-org:v3" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    <!---This should be added ----> 
    xmlns:x="urn:bccdx.ca"> 
    <!---And distributionStatus should be prefixed with x: ----> 
    <x:distributionStatus> 
     <x:receivedTime value="2017-02-23T00:00:00-05:00"/> 
    </x:distributionStatus> 
</RCMR_IN000030UV01> 

首先我会注意到这两个XML文件是语义相同。在第一种情况下,命名空间"urn:bccdx.ca"被声明为实际需要的最低元素上的默认命名空间。在第二种情况下,它是在文件开头用前缀定义的。无论如何,元素<distributionStatus>及其子元素都将以正确的名称空间结束。

因此,您可以简单地接受XML为原样。

如果由于某种原因,你必须有出现在与x:前缀的XML开头的命名空间,您可以将[XmlNamespaceDeclarations]属性添加到您的RCMR_IN000030UV01强迫你的命名空间在更高级别声明:

public partial class RCMR_IN000030UV01 
{ 
    [XmlNamespaceDeclarations] 
    public XmlSerializerNamespaces xmlsn 
    { 
     get 
     { 
      var ns = new XmlSerializerNamespaces(); 
      ns.Add("x", "urn:bccdx.ca"); 
      return ns; 
     } 
     set 
     { 
      // Do nothing - fake property. 
     } 
    } 
} 

docs解释的,这个属性

指定目标属性,参数,返回值,或类成员包含与XML文档中使用的名称空间关联的前缀。

现在您的服务应该根据需要使用根元素上的名称空间返回XML。

+1

这是一个很好的答案,所有的假设都没有了(我编辑了原始问题以包含'XmlSerializerFormat'声明)。我添加了建议的'[XmlNamespaceDeclarations]'属性,它工作。我同意这两种情况下的XML都是正确的,但是规范的一部分就是这样。 – Bensonius