如何使用 DataContractSerializer 从文件中反序列化 WCF 肥皂响应消息?

Posted

技术标签:

【中文标题】如何使用 DataContractSerializer 从文件中反序列化 WCF 肥皂响应消息?【英文标题】:How to deserialize a WCF soap response message from a file with DataContractSerializer? 【发布时间】:2017-09-30 04:49:05 【问题描述】:

当我调用 Web 服务操作时,WCF 使用 DataContractSerializer 将消息反序列化到代理类:为什么我不能这样做?

这是 ActLoginResponse.xml 文件中的肥皂消息:

<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:PlotiIntf" xmlns:ns2="urn:PlotiIntf-IPloti" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"/>
    <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <ns2:ActLoginResponse>
            <return>
                <ResultCode>0</ResultCode>
                <ResultMessage>Login et password correct.</ResultMessage>
                <Acteur>
                    <Id>IMT_706</Id>
                    <Nom>IMA PROTECT</Nom>
                    <Prenom/>
                    <nbFI>0</nbFI>
                    <FonctionActeur>TS</FonctionActeur>
                    <Timeout>30</Timeout>
                </Acteur>
                <ZneGeoList xsi:nil="true"/>
            </return>
        </ns2:ActLoginResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

对应的 ActLoginResponse 类的 WCF 代理代码是:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName="ActLoginResponse", WrapperNamespace="urn:PlotiIntf-IPloti", IsWrapped=true)]
public partial class ActLoginResponse 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
    public Ploti.PlotiClient.LoginResponseType @return;

    public ActLoginResponse() 
    

    public ActLoginResponse(Ploti.PlotiClient.LoginResponseType @return) 
        this.@return = @return;
    

所以我需要将 XML 解析为 ActLoginResponse 类型的对象实例。

这是我执行解析的方式:

        ActLoginResponse body;
        FileStream stream = new FileStream("Requests\\ActLoginResponse.xml", FileMode.Open);
        XmlReader xmlReader = XmlReader.Create(stream);

        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();

        // the the reader is on the element ActLoginResponse (that is confirmed by a Log.Debug( xmlReader.ReadOuterXml());

        // I create The DataContractSerializer: exception if nampespace is not specified
        DataContractSerializer dataContract = new `DataContractSerializer`(typeof(ActLoginResponse), "ActLoginResponse", "urn:PlotiIntf-IPloti");

        ActLoginResponse actLogin = dataContract.ReadObject(xmlReader, true);

创建了 actLogin 对象,但内容 actLogin.return 始终为 NULL !我错过了什么吗?

【问题讨论】:

您是否定义了 LoginResponseType 类的属性?如果没有,那么它将无法将 xml 中的值反序列化为对象。 是的,所有属性都已定义,因为 LoginResponseType 是在将 WSDL 作为服务引用时生成的类。当我使用 Web 服务时,LoginResponseType 是从从网络接收到的 SOAP 响应反序列化的。我想从文件中做同样的事情。 什么是来自 wcf 客户端 Web 服务调用的响应?您是指 WCF 服务响应吗? 对不起我的英文,我更正了文字。 你能给我你的代码示例吗? 【参考方案1】:

我使用了您从另一个问题中提供的 WSDL,并从中创建了一个代理类。

使用上面的 XML,我似乎没有通过以下方式反序列化到 ActLoginResponse 的问题:

Message m = Message.CreateMessage(XmlReader.Create("C:\\testSvc\\login.xml"), int.MaxValue, MessageVersion.Soap11);
SoapReflectionImporter importer = new SoapReflectionImporter(new SoapAttributeOverrides(), "urn:PlotiIntf-IPloti");
XmlTypeMapping mapp = importer.ImportTypeMapping(typeof(ActLoginResponse));
XmlSerializer xmlSerializer = new XmlSerializer(mapp); //typeof(T), xr
var o = (ActLoginResponse)xmlSerializer.Deserialize(m.GetReaderAtBodyContents());

reference

【讨论】:

我意识到这是一个较老的问题,但是没有 WSDL,很难使用您的答案。【参考方案2】:

您应该能够在SoapReflectionImporter 的帮助下使用XmlSerializer 来完成此操作。

var importer = new SoapReflectionImporter("urn:PlotiIntf-IPloti");
var mapping = importer.ImportTypeMapping(typeof(ActLoginResponse));
var serializer = new XmlSerializer(mapping);
var response = serializer.Deserialize(reader) as ActLoginResponse;

SoapReflectionImporter 类提供类型映射到 SOAP 编码的消息部分,如 Web 服务描述中所定义 语言 (WSDL) 文档。仅在 Web 服务或客户端时使用 指定 SOAP 编码,如 SOAP 1.1 的第 5 节所述 规范。

以下命令用于从 WSDL 生成客户端合同

SvcUtil.exe IPlotiservice.wsdl /t:code /serviceContract

【讨论】:

【参考方案3】:

这是一个旧的,但它是我第一次在 Google 上搜索如何反序列化对象,所以我认为在 .NET Core 中发布对我有用的解决方案是值得的。

在我们的例子中,我们使用 svcutil 工具从 WSDL 生成代码,然后使用XmlSerializer,但它抛出了一个无效的操作异常。解决方法是将XmlRoot 属性添加到我们的对象(即肥皂信封的第一个元素)。

所以我们必须像这样装饰对象:

    [System.Xml.Serialization.XmlRoot(ElementName = "Foo", Namespace = "ns")]
    public partial class FooType
    
    

然后我们可以像这样反序列化:

            using var stream = new MemoryStream(Encoding.UTF8.GetBytes(/* stream object */));
            using var message = Message.CreateMessage(XmlReader.Create(stream), int.MaxValue, MessageVersion.Soap11);
            using var xmlStream = message.GetReaderAtBodyContents();

            var serializer = new XmlSerializer(typeof(FooType));
            var obj = serializer.Deserialize(xmlStream);

希望这对其他人有所帮助:)

【讨论】:

只是一点点改进;我在不修改数据类型的情况下让它工作。只需将序列化程序更改为var serializer = new XmlSerializer(typeof(FooType), null, null, new XmlRootAttribute("Foo"), "ns");

以上是关于如何使用 DataContractSerializer 从文件中反序列化 WCF 肥皂响应消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?