反序列化肥皂消息

时间:2011-04-26 17:34:55

标签: c# soap xml-serialization deserialization

我有一个提供商extern给我发送xml for test

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
   <AVCabeza transactionID="000032" xmlns="http://webservices.patito/Core/">
   <Solicitor entityID="WEST" systemType="WEB" />   
  </AVCabeza>
</soap:Header>
<soap:Body>
    <Availability xmlns:a="http://webservices.patito/Availability/" 
      xmlns:hc="http://webservices.patito/Common/" summaryOnly="true" 
      xmlns="http://webservices.patito/og/Availability.wsdl">
     <a:AvailabilityDetail availReqType="Room">
       <a:Estadia>
        <hc:StartDate>2009-01-05T00:00:00.0000000-05:00</hc:StartDate>
          <hc:EndDate>2009-01-06T00:00:00.0000000-05:00</hc:EndDate>
       </a:Estadia>
       <a:HotelSearchCriteria>              
            <a:HotelRef chainCode="WC"/>            
       </a:HotelSearchCriteria>
      </a:AvailabilityDetail>
     </Availability>
  </soap:Body>
</soap:Envelope>

我想反序列化,所以我做了

1)我使用xsd生成c#class

2)使用类generate创建一个新的项目类库。

结构

WebServicesExterns(项目)       - &GT;服务(文件夹)         ---&GT;全班

例如

namespace WebServicesExterns.Services

<System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42"), _
 System.SerializableAttribute(), _
 System.Diagnostics.DebuggerStepThroughAttribute(), _
 System.ComponentModel.DesignerCategoryAttribute("code"), _
 System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://webservices.patito/Availability.wsdl")> _
Partial Public Class Availability




'''<comentarios/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42"),  _
System.SerializableAttribute(),  _
System.Diagnostics.DebuggerStepThroughAttribute(),  _
System.ComponentModel.DesignerCategoryAttribute("code"),  _
System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://webservices.patito/Core/"),  _
System.Xml.Serialization.XmlRootAttribute([Namespace]:="http://webservices.patito/Core/", IsNullable:=false)>  _
Partial Public Class AVCabeza

3)为try deserializer

创建测试类之后
using WebServicesExterns.Services;
using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
using NUnit.Framework;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Soap;


    [Test()]
    public void ShouldDeserializerSoapMessage()
    {
        var message = SoapToFromFile(@"C:\rq\Availability.xml");
        Assert.IsNotNull(message);
    }


    public object SoapToFromFile(string filePath)
    {
        IFormatter formatter;
        FileStream fileStream = null;
        Object objectFromSoap = null;            

        try
        {
            fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            formatter = new SoapFormatter();
            objectFromSoap = formatter.Deserialize(fileStream);
        }
        catch (Exception exception)
        {
            throw exception;
        }
        finally
        {
            if (fileStream != null) fileStream.Close();
        }
        return objectFromSoap;
    }

所以,返回该错误

解析错误,没有与Xml键“AVCabeza”“_ P1”关联的程序集

调试我创建的_P1等于“http://webservices.patito/Core/”

显然未找到“Type”AVCabeza类

怎么了?

新更新

看那是提供商给我的

具有该结构的一个文件夹

root
|
--  WSDL_XSD
|    |-XSD
|    |   files with extension .xsd
|    | 
|    --WS
|        files with extension .wsdl
|-- XMLSamples
     |-files with xml extension that contain soap messsages

我删除了xml(前面的例子)头

<?xml version="1.0" encoding="utf-8"?>
<Availability xmlns:a="http://webservices.patito/Availability/" 
      xmlns:hc="http://webservices.patito/Common/" summaryOnly="true" 
      xmlns="http://webservices.patito/og/Availability.wsdl">
     <a:AvailabilityDetail availReqType="Room">
       <a:Estadia>
        <hc:StartDate>2009-01-05T00:00:00.0000000-05:00</hc:StartDate>
          <hc:EndDate>2009-01-06T00:00:00.0000000-05:00</hc:EndDate>
       </a:Estadia>
       <a:HotelSearchCriteria>              
            <a:HotelRef chainCode="WC"/>            
       </a:HotelSearchCriteria>
      </a:AvailabilityDetail>
</Availability>

并尝试获取可反序列化的可用性对象但未通过此标记

not expected "<Availability .."

现在在wsdl_xsd - &gt; ws - &gt;我看到可用性存在所以我认为什么可用性包装到availabilitydetail(真实请求),这是我无法删除的对象 可用性标记,因为它具有childs标记的命名空间spacefications

怎么想呢?

也许如果我删除可用性并插入命名空间(不知何故)我可以得到我的反序列化器对象

2 个答案:

答案 0 :(得分:3)

SoapFormatter不是XML Serializer。您应该使用XmlSerializer类。

此外,这是一个完整的SOAP消息。让他们为您提供WSDL并使用“添加服务参考”会更好。这将为您提供将为您执行序列化和反序列化的类。

答案 1 :(得分:2)

当您使用xsd.exe从该XML文档生成C#类时,在第一步中您将获得5个单独的.xsd文件, XSD架构从邮件中“推断”。 (有许多XSD文件,因为您在该消息中使用了大量的XML命名空间)

特别是,XSD.exe将生成用于描述SOAP Envelope的代码,包括正文和标题。这可能不是您想要或不需要做的事情,但xsd.exe工具推断整个XML文档的类型。

此外,xsd.exe中的推理引擎是 不精确。例如,Estadia元素的“StartDate”和“EndDate”子元素似乎是日期。但xsd.exe不会做出这样的假设;它将生成一个XML模式,将这些内容标记为 strings 。 xsd.exe在推断时还有其他类似的假设。在所有情况下,您可能希望修改生成的xsd文件,以匹配您真正期望的内容。对于StartDate和EndDate,您希望将类型从xs:string修改为xs:dateTime

此时,您可以使用/ c开关在.xsd文件上再次运行xsd.exe ,以生成.cs源代码。编译 以获取可用于序列化的类。

要使用生成的代码反序列化,您可以执行以下操作:

  XmlSerializer s1 = new XmlSerializer(typeof(Carlos.Envelope));
  Envelope envelope = null;
  using(var reader= System.IO.File.OpenText("SampleMessage.xml"))
  {
      envelope = (Envelope) s1.Deserialize(reader);
  }

然后,您可以打开该Envelope对象并获取其中的各种数据。


退后一步,你可以看到你可能不应该这样做。查看示例消息非常有用且方便,以向您展示线路上应该是什么样的内容。但是当生成代码来处理序列化到这些消息的类时,最好从源XSD开始 - 这可能在服务端可用。这就是约翰桑德斯在回答中所说的话。

如果您的员工可以生成示例消息,那么他们可能拥有该消息的XSD(或等效的WSDL)。这将消除您推断xsd的要求,然后通过我上面描述的不精确的过程修改它来改变破坏的假设。

您需要这样做的唯一时间是,如果您以某种方式丢失了原始XSD / WSDL,并且您需要重新生成它。