c# - 将多个命名空间添加到 MessageContract WCF 响应对象 (MessageBodyMember)

标签 c# xml wcf serialization messagecontract

我们有一个包含以下契约(Contract)的 WCF 设置:

    [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 架构生成的类。
  • 然后,我们更改架构以使用自定义命名空间添加自定义元素来区分它并重新生成类。
  • 效果很好。

它补充说:

[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{...}
}

这就是我们想要的。

然后在 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>

注意带有前缀的 urn:bccdx.ca

我想知道,如果我们可以添加多个命名空间,并通过契约将前缀添加到生成的序列化消息 XML 中,该怎么办?我在网上看到了覆盖默认序列化程序的提示,但我不想这样做。之前肯定已经考虑过并处理过这个问题吗?

最佳答案

首先,我假设在您的服务契约(Contract)中的某个位置,您指定使用 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。

如果由于某种原因,您必须在 XML 的开头显示 namespace x:前缀,您可以添加 [XmlNamespaceDeclarations] 属性(property)给您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 中所述,这个属性

Specifies that the target property, parameter, return value, or class member contains prefixes associated with namespaces that are used within an XML document.

现在,您的服务应该根据需要返回带有根元素上的命名空间的 XML。

关于c# - 将多个命名空间添加到 MessageContract WCF 响应对象 (MessageBodyMember),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42307941/

相关文章:

c# - 如何在 Windows Phone 8 中释放图像缓存/内存?

c# - 如何以编程方式确定我的处理器类型?

安卓自定义主题

C# 动态程序集无法创建新对象并加载到字段

c# - 如何通过 PublicKeyToken 从 GAC 中批量卸载程序集?

xml - 错误 : The prefix "xsd" for element "xsd:schema" is not bound

java - Spring : java. lang.NoSuchMethodError : javax. persistence.Table.indexes()[Ljavax/persistence/Index;

c# - 使用 ACL 保护 WCF 配置文件

c# - 在 Windows Process Activation Services (WAS) 和 IIS 7 之间进行选择

wcf - WCF 服务中的 *Result 和 *ResultSpecified 参数?