简体   繁体   English

如何生成具有正确名称空间前缀的SOAP兼容XML响应?

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

I'm writing a small web server (HttpListener) which will ultimately run as part of a Windows service and response to SOAP requests from another application. 我正在编写一个小型Web服务器(HttpListener),该服务器最终将作为Windows服务的一部分运行,并响应来自另一个应用程序的SOAP请求。

I've written the code to decode the SOAP request XML and extract the action, process it and get the result, but can't quite get the response XML to be generated correctly. 我已经编写了用于解码SOAP请求XML并提取操作,对其进行处理并获得结果的代码,但是还无法完全获得正确生成的响应XML。

I've like to avoid generating each element individually since the Types of the response may vary and I don't want to have to code every variant into the web server and would prefer not to have to delve into Reflection and walk the Type structure to output the values. 我想避免单独生成每个元素,因为响应的类型可能会有所不同,并且我不想将每个变量都编码到Web服务器中,并且不想去深入研究Reflection并使用Type结构来输出值。 I'd prefer to use something simple like the XmlSerializer Serialize method (which presumably is walking the Type structure), but it's not clear if it has enough control. 我更喜欢使用类似XmlSerializer的Serialize方法(大概在遍历Type结构)之类的东西,但是尚不清楚它是否具有足够的控制权。

The output I'm trying to produce in my test program is: 我想在测试程序中产生的输出是:

<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>

The output I'm getting is: 我得到的输出是:

<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>

This is the current test program: 这是当前的测试程序:

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

Can this be done with Serialize or do have to do it with Reflection and, effectively, reproduce what the SOAP responder in IIS is already doing? 可以使用序列化来完成此操作,还是必须使用反射来完成此操作,并有效地重现IIS中SOAP响应器已在执行的操作?

FYI, I also tried setting up a Type mapping... 仅供参考,我还尝试设置类型映射...

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

... but the resultant XML was totally different and, although it didn't produce an error, also didn't decode in the calling application; ……但是生成的XML完全不同,尽管它没有产生错误,但是在调用的应用程序中也没有解码; a null value was returned 返回一个空值

<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>

I like to use xml linq. 我喜欢使用xml linq。 For complicated headers a namespaces I just parse a string to get desired results. 对于复杂的标头,我只解析一个字符串即可获得所需的结果。 See code below : 参见下面的代码:

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