【问题标题】:Wrap XML in SOAP envelope in .net在 .net 中将 XML 包装在 SOAP 信封中
【发布时间】:2014-02-26 21:42:58
【问题描述】:

我需要帮助我将 XML 包装到第三方 SOAP 服务器的 SOAP 信封中。第三方为入站请求和出站响应提供了 xsd 文件。我已经使用 xsd 工具获取了这些 XSD 文件并创建了它们的 C# 类。我的问题是我需要用 SOAP 信封包装序列化请求,但我不知道从哪里开始。我正在查看 Microsoft Web Service Enhancements 3,但它表示它仅适用于 .net 2.0 和 VS2005。我正在使用 VS2012 和 .net 4.5。另外,我研究过通过 Web 服务连接到服务器,但它似乎不兼容并且没有 WSDL

以下是 SOAP 服务器对入站请求的期望示例。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<GetBasicData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="CRS610MI">
<CONO xmlns="">1</CONO>
<CUNO xmlns="">12345</CUNO>
</GetBasicData>
</soap:Body>
</soap:Envelope>

这就是序列化的 XML 字符串的样子。

<?xml version="1.0" encoding="utf-8"?>
<GetBasicData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="CRS610MI">
<CONO xmlns="">1</CONO>
<CUNO xmlns="">12345</CUNO>
</GetBasicData>

我用于网络请求和响应的代码。

Byte[] byteArray = System.Text.UTF8Encoding.UTF8.GetBytes(data);

WebRequest webRequest = WebRequest.Create(@"http://myserver:8888");
webRequest.ContentLength = byteArray.Length;
webRequest.ContentType = @"text/xml; charset=utf-8";
webRequest.Headers.Add("SOAPAction", @"http://schemas.xmlsoap.org/soap/envelope/");
webRequest.Method = "POST";

Stream requestStream = webRequest.GetRequestStream();
requestStream.Write(byteArray, 0, byteArray.Length);
requestStream.Close();
requestStream.Dispose();

WebResponse webResponse = webRequest.GetResponse();

Stream responseStream = webResponse.GetResponseStream();

StreamReader streamReader = new StreamReader(responseStream);

String line;

while ((line = streamReader.ReadLine()) != null)
{
    Debug.WriteLine(line);
}

我已经通过将我的序列化字符串替换为第三方提供的示例文件中的文本来测试我的代码,并且它按预期工作。我还拿了我的序列化字符串并将信封文本插入到正确的位置,这也有效,网络请求通过了,我得到了我正在寻找的响应。没有手动将信封文本插入到我的序列化字符串中,我该怎么办。我必须想象有一个方法或类会以标准化的方式为我处理这个问题?

【问题讨论】:

  • “标准化方式”是为服务提供一个WSDL。
  • 顺便说一句,您确定该服务没有 WSDL 吗?尝试使用浏览器,并浏览到服务的地址。如果这不起作用,请尝试将?wsdl 添加到服务 URL 的末尾。

标签: c# xml web-services serialization soap


【解决方案1】:

我能够通过使用 XLST 将 XML 包装在 soap 中来解决这个问题。

这是我的工作测试应用代码

using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Xml.Xsl;


namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            GetBasicData getBasicData = new GetBasicData();
            getBasicData.CONO = "1";
            getBasicData.CUNO = "201702";

            XPathDocument requestXPathDocument;

            if (SerializeIntoRequestXPathDocument(getBasicData, out requestXPathDocument))
            {
                XmlDocument requestXmlDocument;

                if (CreateRequestXMLDocument(requestXPathDocument, @"Z:\Darice\M3 SOAP\GetBasicData.xsl", out requestXmlDocument))
                {
                    XmlDocument responseXmlDocument;

                    if (ExecuteRequestSoap(requestXmlDocument, out responseXmlDocument))
                    {
                        MemoryStream unwrappedMemoryStream;

                        if (UnwrapSoapResponseXmlDocumentIntoMemoryStream(responseXmlDocument, out unwrappedMemoryStream))
                        {
                            GetBasicDataResponse getBasicDataResponse;

                            if (!DeserializeResponseMemoryStream(unwrappedMemoryStream, out getBasicDataResponse))
                            {
                                Debug.WriteLine("FAIL");
                            }
                        }
                    }
                }
            }

            Console.ReadLine();
        }


        //STATIC FUNCTIONS
        private static Boolean CreateRequestXMLDocument(XPathDocument xPathDocument, String xslPath, out XmlDocument xmlDocument)
        {
            try
            {
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (StreamWriter streamWriter = new StreamWriter(memoryStream))
                    {
                        XmlWriter xmlWriter = XmlWriter.Create(streamWriter);

                        XsltSettings xsltSettings = new XsltSettings();
                        xsltSettings.EnableScript = true;

                        XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
                        xslCompiledTransform.Load(xslPath, xsltSettings, null);
                        xslCompiledTransform.Transform(xPathDocument, xmlWriter);

                        memoryStream.Position = 0;

                        using (StreamReader streamReader = new StreamReader(memoryStream))
                        {
                            XmlReader xmlReader = XmlReader.Create(streamReader);

                            xmlDocument = new XmlDocument();
                            xmlDocument.Load(xmlReader);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception);

                xmlDocument = null;

                return false;
            }

            return true;
        }

        private static Boolean DeserializeResponseMemoryStream<T>(MemoryStream memoryStream, out T xmlObject)
        {
            try
            {
                using (StreamReader streamReader = new StreamReader(memoryStream))
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

                    using (XmlReader xmlReader = XmlReader.Create(streamReader))
                    {
                        xmlObject = (T)xmlSerializer.Deserialize(xmlReader);
                    }
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception);

                xmlObject = default(T);

                return false;
            }

            return true;
        }

        private static Boolean ExecuteRequestSoap(XmlDocument requestXmlDocument, out XmlDocument responseXmlDocument)
        {
            try
            {
                Byte[] byteArray = UTF8Encoding.UTF8.GetBytes(requestXmlDocument.OuterXml);

                WebRequest webRequest = WebRequest.Create(Properties.Resources.SoapServerAddress);
                webRequest.ContentLength = byteArray.Length;
                webRequest.ContentType = @"text/xml; charset=utf-8";
                webRequest.Headers.Add("SOAPAction", @"http://schemas.xmlsoap.org/soap/envelope/");
                webRequest.Method = "POST";

                using (Stream requestStream = webRequest.GetRequestStream())
                {
                    requestStream.Write(byteArray, 0, byteArray.Length);

                    using (WebResponse webResponse = webRequest.GetResponse())
                    {
                        using (Stream responseStream = webResponse.GetResponseStream())
                        {
                            using (StreamReader streamReader = new StreamReader(responseStream))
                            {
                                responseXmlDocument = new XmlDocument();
                                responseXmlDocument.LoadXml(streamReader.ReadToEnd());
                            }
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception);

                responseXmlDocument = null;

                return false;
            }

            return true;
        }

        private static Boolean SerializeIntoRequestXPathDocument<T>(T dataObject, out XPathDocument xPathDocument)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (StreamWriter streamWriter = new StreamWriter(memoryStream))
                    {
                        xmlSerializer.Serialize(streamWriter, dataObject);

                        memoryStream.Position = 0;

                        using (StreamReader streamReader = new StreamReader(memoryStream))
                        {
                            memoryStream.Position = 0;

                            xPathDocument = new XPathDocument(streamReader);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception);

                xPathDocument = null;

                return false;
            }

            return true;
        }

        private static Boolean UnwrapSoapResponseXmlDocumentIntoMemoryStream(XmlDocument responseXmlDocument, out MemoryStream memoryStream)
        {
            try
            {
                XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(responseXmlDocument.NameTable);
                xmlNamespaceManager.AddNamespace("tns", "CRS610MI");
                xmlNamespaceManager.AddNamespace("SOAP", @"http://schemas.xmlsoap.org/soap/envelope/");

                XmlNode xmlNode = responseXmlDocument.SelectSingleNode(@"/SOAP:Envelope/SOAP:Body/tns:GetBasicDataResponse", xmlNamespaceManager);

                memoryStream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(xmlNode.OuterXml));
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception);

                memoryStream = null;

                return false;
            }

            return true;
        }
    }
}

这是 XSL 代码

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:crs="CRS610MI" exclude-result-prefixes="crs">
<xsl:output method="xml"/>
<xsl:template match="/">
  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <soap:Body>
    <xsl:apply-templates select="node()|@*"/>
    </soap:Body>
  </soap:Envelope>
</xsl:template>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

【讨论】:

    【解决方案2】:

    如果服务提供者不提供 WSDL,那么您不应该与他们做生意。这不是火箭科学,它是 SOAP Web 服务工作的标准方式。十多年来,它只是一个标准。我很想知道这个服务提供商在其他方面是不称职的。

    如果您别无选择,只能与不称职的商业伙伴做生意,那么

    1. 祝你好运
    2. 创建您的自己的 WSDL 以匹配他们的服务,然后使用“添加服务引用”创建与服务通信所需的代理类。

    【讨论】:

    • 是的,我意识到了这一点。这是一个很久没有更新的旧服务,但它仍然有效。还有一种替代方法,即直接调用 api,然后从一个巨大的单行字符串中解析字段,该字符串没有关于每个值是什么的文档。我想,两害相权取其轻。
    • 为什么需要更新?为什么它一开始就没有 WSDL?我的意思是,实际上,WSDL 从一开始就是 SOAP 的一部分。也许他们只是丢失了 WSDL?或者,如果您对服务非常了解,可以尝试手动伪造信封,也许您可​​以创建一个 WSDL 来做同样的事情?然后你可以给服务提供者 WSDL 的礼物。
    • 当 WSDL 被证明是 Java 和 .NET 之间的又一次互操作失败时,有时需要使用 raw soap 交换,并且您无法让提供者更改它,因为“它在soapUI 和日食”。
    【解决方案3】:

    你需要用 MessageContract for soap 标记你的类

    [MessageContract]
    public class ExampleResponse
    {
       private string _myResponse = String.Empty;
    
       [MessageBodyMember(Name = "ResponseToGive", Namespace = "http://myserver:8888")]
       public string ResponseToGive
       {
         get { return _myResponse; }
         set { _myResponse = value; }
       }
    }
    

    【讨论】:

    • 我尝试将消息协定和消息正文成员添加到属性中,但序列化的字符串看起来与以前一样。我正在使用 XML 序列化程序,我应该使用其他东西吗?
    • 我不在电脑前,所以我不能给你确切的信息,但是如果你谷歌 c#soap Message.CreateMessage 会看到该怎么做。
    【解决方案4】:

    我不明白为什么有些人如此坚决以至于你必须使用 WSDL。 WSDL 只是为了让您可以调用它们的方法并使用它们的实体,并且是可选的。

    我已经通过转到他们服务的确切网址来实现这一点,例如 https://something.com/SomeService/TheService.asmx?method=DoSomething

    并且只是分析他们的 API 定义的确切标头和 XML,包括 SOAP 信封。第一部分应该是标头信息,然后是 XML。完全按照他们指定的方式创建 XML,包括信封标签。对于 Header:POST、Host、Content-Type 和 SOAPAction,是最重要的。我发现有些服务器不需要 Content-Length,即使它已在其 API 中列出。

    这里是一些示例代码

    public void PostXMLData(string serviceUrl, XDocument requestXML)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serviceUrl);
            req.Method = "POST";
            req.Host = "SOMETHING";
            req.ContentType = "text/xml; charset=utf-8";
            req.Headers.Add("SOAPAction", "SOMETHING");
            req.Accept = "text/xml";
    
            using (Stream stream = req.GetRequestStream())
            {
                requestXML.Save(stream);
            }
    
            using (WebResponse resp = req.GetResponse())
            {
                using (StreamReader rd = new StreamReader(resp.GetResponseStream()))
                {
                    var result = rd.ReadToEnd();
                    if (result.Contains("error"))
                    {
                        throw new Exception($"XML Submission Failed: {result}");
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多