XmlSerializer反序列化失败

时间:2010-04-06 22:56:22

标签: c# xml xmlserializer

我有来自第三方服务器的wsdl。跑了svcutil并最终得到了一套

XmlNode AMethod(object Request);

方法。有一个单独的100页pdf描述每个方法的响应/请求对象

我的想法是换行Web方法并使用XmlSerializer返回强类型对象。返回的xml看起来像这样(我删除了soap标题):

<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:type="ResponseExt" 
        xmlns="http://www.thirdparty.com/lr/">
  <Code>0</Code>
  <Message>SUCCESS</Message>
  <SessionId>session_token</SessionId>
</Response>

看起来很简单。创建了一个类(来自文档/电线捕获):

[XmlRoot("Response")]
//EDIT added XmlType
[XmlType("ResponseExt", Namespace = "http://www.thirdparty.com/lr/")]
public class MyClass {
    public string Code {get; set;}
    public string Message {get; set;}
    public string SessionId {get; set;}
}

处理时间:

//XmlNode node = xml from above
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlNodeReader reader =  new XmlNodeReader(node);
Myclass myclass = serializer.Deserialize(reader) as MyClass

最后一行是爆炸的内部异常消息:无法识别指定的类型:name ='ResponseExt',namespace ='http://www.thirdparty.com/lr/',<Response xmlns=''&gt;。
我无法弄清楚如何让Serializer感到高兴,这两者究竟是什么意思

  

的xsi:type = “ResponseExt”   的xmlns =“http://www.thirdparty.com/lr/

一如既往地赞赏任何建议和指针


编辑:接受以下答案。

我还是异常,直到我找到了这个,希望它能节省一些时间。 我开始倒退了。在电线上捕获xml。反序列化到我创建的具有正确属性的类:像魅力一样工作。再次尝试从webservice - 例外。由于某种原因,XmlSerializer无法识别ResponseExt。

XmlSerializer serializer = new XmlSerializer(typeof(Response));
XmlNode node = (XmlNode)results[0];
XmlDocument doc = new XmlDocument();
doc.LoadXml(node.OuterXml); //reload node
XmlNodeReader reader = new XmlNodeReader(doc.FirstChild); //there is only one node
Response rsp = serializer.Deserialize(reader) as Response; //works

编辑:基础问题wsdl文件未完成。在花了两天时间找到这个(丑陋的)解决方法之后,第三方供应商提供了完整 WSDL,其中所有类型都反序列化而没有错误。

1 个答案:

答案 0 :(得分:1)

为什么在使用WSDL时手动反序列化XML?

如果您有WSDL,请使用svcutil.exe工具或wsdl.exe工具为线路上发送和接收的XML消息生成代理类和DTO。

Web服务工具包或“堆栈”的目的是为您提供此功能,这样您就不必手动编写类和XML序列化代码。

你尝试过这个吗?您是否尝试通过其中一种工具运行WSDL?或者您是否尝试在Visual Studio中“添加Web引用”?


更新问题后,我建议您修改WSDL,而不是编写自定义代码。您可以为服务生成自定义WSDL,这将正确生成所需的代理类。如果您不需要所有100种方法(或者有多种方法),请将它们排除在外。如果需要方法中的自定义对象,请定义与该对象对应的complexType。这比为每种方法手动编写XML反序列化代码更简单,更可靠。


如果您不喜欢这个想法,并希望坚持手动编写XML反序列化代码,那么您需要做两件事:

  1. 附上a namespace to the XmlRoot attribute

  2. 将您的班级名称更改为ResponseExt,并从名为Response的班级中派生。使用XmlInclude属性装饰该Response类。这符合the Xml Serializer with the xsi:type used in the XML fragment的使用。

  3. 在代码中看起来像这样:

    [XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")]
    public class ResponseExt : Response {
    }
    
    [XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")]
    [XmlInclude(typeof(ResponseExt))]
    public class Response {
        public string Code {get; set;}
        public string Message {get; set;}
        public string SessionId {get; set;}
    }
    
    public class XsiType
    {
        public static void Main(string[] args)
        {
            try
            {
                string filename = "XsiType.xml";
                XmlSerializer s1 = new XmlSerializer(typeof(Response));
                ResponseExt r = null;
                using(System.IO.StreamReader reader= System.IO.File.OpenText(filename))
                {
                    r= (ResponseExt) s1.Deserialize(reader);
                }
    
                var builder = new System.Text.StringBuilder();
                var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
                using ( var writer = System.Xml.XmlWriter.Create(builder, xmlws))
                {
                    //s1.Serialize(writer, r, ns);
                    s1.Serialize(writer, r);
                }
                string xml = builder.ToString();
                System.Console.WriteLine(xml);
    
            }
            catch (System.Exception exc1)
            {
                Console.WriteLine("Exception: {0}", exc1.ToString());
            }
        }
    }
    

    相关:How can I force the use of an xsi:type attribute?