1

我有来自第三方服务器的 wsdl。运行 svcutil 并最终获得了一组

XmlNode AMethod(object Request);

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

我的想法是包装 web 方法并使用 XmlSerializer 返回强类型对象。返回的 xml 看起来像这样(我删除了肥皂标题):

<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/',at<Response xmlns='' >。
我不知道如何让 Serializer 开心,这两个到底是什么意思

xsi:type="ResponseExt" xmlns="http://www.thirdparty.com/lr/

一如既往地感谢任何建议和指针


编辑:下面接受的答案。

我仍然遇到异常,直到我发现这个,希望它可以节省一些时间。我开始向后工作。在网络上捕获的 xml。反序列化为我创建的具有正确属性的类:像魅力一样工作。从 web 服务再次尝试 - 异常。由于某种原因,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 文件不完整。在花了 2 天时间并找到了这个(丑陋的)解决方法之后,第三方供应商提供了完整的WSDL,其中包含所有类型的反序列化且没有错误。

4

1 回答 1

1

当您有 WSDL 时,为什么要手动反序列化 XML?

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

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

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


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


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

  1. 命名空间附加到 XmlRoot 属性

  2. 将您的类的名称更改为ResponseExt,并从名为 的类派生它Response使用XmlInclude属性装饰该 Response 类。这使 Xml Serializer 的使用与 XML 片段中使用的 xsi:type保持一致。

它在代码中看起来像这样:

[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());
        }
    }
}

相关:如何强制使用 xsi:type 属性?

于 2010-04-07T00:34:01.787 回答