簡體   English   中英

如何生成具有正確名稱空間前綴的SOAP兼容XML響應?

[英]How do I generate a SOAP-compatible XML response with correct namespace prefixes?

我正在編寫一個小型Web服務器(HttpListener),該服務器最終將作為Windows服務的一部分運行,並響應來自另一個應用程序的SOAP請求。

我已經編寫了用於解碼SOAP請求XML並提取操作,對其進行處理並獲得結果的代碼,但是還無法完全獲得正確生成的響應XML。

我想避免單獨生成每個元素,因為響應的類型可能會有所不同,並且我不想將每個變量都編碼到Web服務器中,並且不想去深入研究Reflection並使用Type結構來輸出值。 我更喜歡使用類似XmlSerializer的Serialize方法(大概在遍歷Type結構)之類的東西,但是尚不清楚它是否具有足夠的控制權。

我想在測試程序中產生的輸出是:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetUsernamesResponse xmlns="http://tempuri.org/">
      <GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2"
            xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:Results xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
          <b:string>Kermit.The.Frog</b:string>
          <b:string>Miss.Piggy</b:string>
        </a:Results>
      </GetUsernamesResult>
    </GetUsernamesResponse>
  </s:Body>
</s:Envelope>

我得到的輸出是:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetUsernamesResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://tempuri.org/">
      <GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2" 
                xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays" 
                xmlns="">
        <Results>
          <string>Kermit.The.Frog</string>
          <string>Miss.Piggy</string>
        </Results>
      </GetUsernamesResult>
    </GetUsernamesResponse>
  </s:Body>
</s:Envelope>

這是當前的測試程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApp2
{
    public class GetUsernamesResponse
    {
        public List<string> Results { get; set; }
    }

    public class GetUsernamesResult : GetUsernamesResponse {}

    public class Program
    {
        private const string ns_t = "http://tempuri.org/";
        private const string ns_s = "http://schemas.xmlsoap.org/soap/envelope/";
        private const string ns_i = "http://www.w3.org/2001/XMLSchema-instance";
        private const string ns_a = "http://schemas.datacontract.org/2004/07/ConsoleApp2";
        private const string ns_b = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";

        private static void Main(string[] args)
        {
            var r = new GetUsernamesResult()
            {
                Results = new List<string>
                {
                    "Kermit.The.Frog",
                    "Miss.Piggy"
                }
            };

            var ns = new XmlSerializerNamespaces();
            ns.Add("i", ns_i);
            ns.Add("a", ns_a);
            ns.Add("b", ns_b);

            var oSerializer = new XmlSerializer(typeof(GetUsernamesResult));
            using (var sw = new StringWriter())
            {
                var xw = XmlWriter.Create(
                    sw,
                    new XmlWriterSettings()
                    {
                        OmitXmlDeclaration = true,
                        Indent = true,
                        ConformanceLevel = ConformanceLevel.Fragment,
                        NamespaceHandling = NamespaceHandling.OmitDuplicates,
                    });
                xw.WriteStartElement("s", "Envelope", ns_s);
                xw.WriteStartElement("s", "Body", ns_s);
                xw.WriteStartElement($"GetUsernamesResponse", ns_t);
                xw.WriteAttributeString("xmlns", "i", null, ns_i);
                oSerializer.Serialize(xw, r, ns);
                xw.WriteEndElement();
                xw.WriteEndElement();
                xw.WriteEndElement();
                xw.Close();
                Console.WriteLine(sw);
            }
            Console.ReadKey();
        }
    }
}

可以使用序列化來完成此操作,還是必須使用反射來完成此操作,並有效地重現IIS中SOAP響應器已在執行的操作?

僅供參考,我還嘗試設置類型映射...

var mapping = new SoapReflectionImporter().ImportTypeMapping(typeof(BarcodeProductionGetUsernamesResult));
var oSerializer = new XmlSerializer(mapping);

……但是生成的XML完全不同,盡管它沒有產生錯誤,但是在調用的應用程序中也沒有解碼; 返回一個空值

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetUsernamesResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
      <GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays" id="id1" xmlns="">
      <Results href="#id2" />
    </GetUsernamesResult>
    <q1:Array id="id2" xmlns:q2="http://www.w3.org/2001/XMLSchema" q1:arrayType="q2:string[2]" xmlns:q1="http://schemas.xmlsoap.org/soap/encoding/">
        <Item xmlns="">Kermit.The.Frog</Item>
        <Item xmlns="">Miss.Piggy</Item>
      </q1:Array>
    </GetUsernamesResponse>
  </s:Body>
</s:Envelope>

我喜歡使用xml linq。 對於復雜的標頭,我只解析一個字符串即可獲得所需的結果。 參見下面的代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();

            XDocument doc = MySerializer<MyClass>.GetXElement(myClass);
        }
    }

    public class MySerializer<T> where T : new()
    {
        static string xml =
           "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
           "    <s:Body>" +
           "       <GetUsernamesResponse xmlns=\"http://tempuri.org/\">" +
           "          <GetUsernamesResult xmlns:a=\"http://schemas.datacontract.org/2004/07/ConsoleApp2\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
           "             <a:Results xmlns:b=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">" +
           "             </a:Results>" +
           "          </GetUsernamesResult>" +
           "      </GetUsernamesResponse>" +
           "   </s:Body>" +
           "</s:Envelope>";
        public static XDocument GetXElement(T myClass)
        {


            XDocument doc = XDocument.Parse(xml);

            XElement results = doc.Descendants().Where(x => x.Name.LocalName == "Results").FirstOrDefault();
            XNamespace ns_b = results.GetNamespaceOfPrefix("b");

            StringWriter sWriter = new StringWriter();
            XmlWriter xWriter = XmlWriter.Create(sWriter);

            XmlSerializerNamespaces ns1 = new XmlSerializerNamespaces();
            ns1.Add("b", ns_b.NamespaceName);

            XmlSerializer serializer = new XmlSerializer(typeof(T), ns_b.NamespaceName);
            serializer.Serialize(xWriter, myClass, ns1);
            results.Add(XElement.Parse(sWriter.ToString()));

            return doc;
        }

    }
    public class MyClass
    {
        public string test { get; set; }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM