我正在编写一个小型Web服务器(HttpListener),该服务器最终将作为Windows服务的一部分运行,并响应来自另一个应用程序的SOAP请求。
我已经编写了用于解码SOAP请求XML并提取动作,对其进行处理并获得结果的代码,但还不能完全正确地生成响应XML。
我想避免单独生成每个元素,因为响应的类型可能会有所不同,并且我不想将每个变体都编码到Web服务器中,并且不想钻研Reflection并遍历键入结构以输出值。我宁愿使用类似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>
答案 0 :(得分:0)
我喜欢使用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; }
}
}