C#获取客户端调用WebService时生成的原生的请求xml字符串,生成的Xml可以直接在SoapUI中使用
新建Windows窗体应用程序GetRequestRawXmlForWebServiceDemo,将默认的Form1重命名为FormGetRequestRawXml,
FormGetRequestRawXml窗体设计如图:
添加测试可用的webservice【中英文双向翻译】:
http://www.webxml.com.cn/WebServices/TranslatorWebService.asmx?wsdl
同时添加对System.Web的引用
新建Xml和实体类之间的转化以及XML格式化【换行、缩进、对齐】的操作类文件XmlSerializeUtil.cs
类XmlSerializeUtil源程序如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace GetRequestRawXmlForWebServiceDemo
{
/// <summary>
/// XML与实例化类之间的转化
/// </summary>
public sealed class XmlSerializeUtil
{
/// <summary>
/// 类的对象转换为xml字符串,
/// 生成的xml的根节点就是T的类型名称
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static string ObjectToXml<T>(T t, Encoding encoding)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(ms, encoding))
{
xmlSerializer.Serialize(xmlWriter, t);
return encoding.GetString(ms.ToArray()).Trim();
}
}
}
/// <summary>
/// 将指定的对象写入Xml文件
/// 又在MSDN上查找XmlIncludeAttribute的定义如下:允许 XmlSerializer 在它序列化或反序列化对象时识别类型。
/// 所以我想是因为方法返回的类型其实是House类的子类,XmlSerializer在序列化时只能识别父类,而不能识别子类,所以导致序列化的错误。
/// 所以我将[XmlInclude(typeof(SaleHouse))]和[XmlInclude(typeof(RentHouse))]同时加到WebService中,问题解决。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="xmlFilePath"></param>
public static void ObjectToXml<T>(T t, string xmlFilePath, Encoding encoding)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StreamWriter writer = new StreamWriter(xmlFilePath, false, encoding))
{
xmlSerializer.Serialize(writer, t);
writer.Close();
}
}
/// <summary>
/// 将实体对象转换成XML
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="obj">实体对象</param>
public static string XmlSerialize<T>(T obj)
{
try
{
using (StringWriter sw = new StringWriter())
{
Type t = obj.GetType();
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(sw, obj);
sw.Close();
return sw.ToString();
}
}
catch (Exception ex)
{
throw new Exception("将实体对象转换成XML异常", ex);
}
}
/// <summary>
/// xml字符串转实体类,xml字符串的根节点一定要与类名一致,否则将产生错误
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xmlString"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static T XmlToObject<T>(string xmlString, Encoding encoding)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(encoding.GetBytes(xmlString)))
{
return (T)xmlSerializer.Deserialize(ms);
}
}
/// <summary>
/// 将指定路径的xml文件转化为对应的T类型对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xmlFilePath"></param>
/// <returns></returns>
public static T XmlDeSerialize<T>(string xmlFilePath)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (FileStream fs = new FileStream(xmlFilePath, FileMode.Open))
{
return (T)serializer.Deserialize(fs);
}
}
/// <summary>
/// 对xml节点进行换行,格式化对齐操作
/// </summary>
/// <param name="srcXml"></param>
/// <returns></returns>
public static string FormatXml(string srcXml)
{
string formattedXml = IndentedFormat(IndentedFormat(srcXml).Replace("><", ">\r\n<"));
return formattedXml;
}
/// <summary>
/// 对XML字符串进行换行缩进,格式化
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private static string IndentedFormat(string xml)
{
string indentedText = string.Empty;
try
{
XmlTextReader reader = new XmlTextReader(new StringReader(xml));
reader.WhitespaceHandling = WhitespaceHandling.None;
StringWriter indentedXmlWriter = new StringWriter();
XmlTextWriter writer = CreateXmlTextWriter(indentedXmlWriter);
writer.WriteNode(reader, false);
writer.Flush();
indentedText = indentedXmlWriter.ToString();
}
catch (Exception)
{
indentedText = xml;
}
return indentedText;
}
/// <summary>
/// 写入四个缩进字符【空格】
/// </summary>
/// <param name="textWriter"></param>
/// <returns></returns>
private static XmlTextWriter CreateXmlTextWriter(TextWriter textWriter)
{
XmlTextWriter writer = new XmlTextWriter(textWriter);
//将Tab转化为4个空格
bool convertTabsToSpaces = true;
if (convertTabsToSpaces)
{
writer.Indentation = 4;
writer.IndentChar = ' ';
}
else
{
writer.Indentation = 1;
writer.IndentChar = '\t';
}
writer.Formatting = Formatting.Indented;
return writer;
}
}
}
新建类文件SoapUtil.cs,类SoapUtil用于获取客户端调用WebService时生成的原生的请求xml字符串,可以直接在SoapUI中使用。
类SoapUtil源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace GetRequestRawXmlForWebServiceDemo
{
/// <summary>
/// 获取客户端调用WebService时生成的原生的请求xml字符串,可以直接在SoapUI中使用
/// 斯内科 2022-06-19
/// </summary>
public class SoapUtil
{
/// <summary>
/// 获取请求WebService原生的XML
/// </summary>
/// <typeparam name="TWebService">一个WebService类,继承于SoapHttpClientProtocol</typeparam>
/// <param name="methodName">接口方法名</param>
/// <param name="parameters">实参列表需和接口方法定义的参数类型和个数一致,无参数时一定要传入null</param>
/// <param name="defaultNamespace">Xml命名空间,可以是任意的</param>
/// <returns></returns>
public static string GetRawXml<TWebService>(string methodName, object[] parameters, string defaultNamespace = "web") where TWebService : System.Web.Services.Protocols.SoapHttpClientProtocol
{
Type t = typeof(TWebService);
MethodInfo methodInfo = t.GetMethod(methodName);
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
System.Web.Services.WebServiceBindingAttribute webServiceBindingAttribute = t.GetCustomAttribute<System.Web.Services.WebServiceBindingAttribute>();
if (webServiceBindingAttribute == null)
{
throw new Exception($"不是标准的WebService类名,没有找到特性WebServiceBindingAttribute");
}
System.Web.Services.Protocols.SoapDocumentMethodAttribute soapDocumentAttribute = methodInfo.GetCustomAttribute(typeof(System.Web.Services.Protocols.SoapDocumentMethodAttribute))
as System.Web.Services.Protocols.SoapDocumentMethodAttribute;
if (soapDocumentAttribute == null)
{
throw new Exception($"不是标准的WebService接口方法,没有找到特性SoapDocumentMethodAttribute");
}
if (!(parameterInfos.Length == 0 && parameters == null)
&& !(parameters != null && parameterInfos.Length == parameters.Length))
{
throw new Exception($"如果是无参数的方法,传入的参数值必须为null。如果是有参数的方法,实参个数必须与接口定义参数个数一致");
}
//string defaultNamespace = "web";//Xml命名空间,可以是任意的
StringBuilder sb = new StringBuilder();
//methodName方法名下的每个参数名
for (int i = 0; i < parameterInfos.Length; i++)
{
string paraName = parameterInfos[i].Name;
Type type = parameterInfos[i].ParameterType;
if ((type.IsArray || type.IsClass) && type != typeof(string))
{
string xmlTemp = XmlSerializeUtil.XmlSerialize(parameters[i]);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlTemp);
string parameterXml = xmlDoc.DocumentElement.InnerXml;
sb.AppendLine($"<{defaultNamespace}:{paraName}>{parameterXml}</{defaultNamespace}:{paraName}>");
}
else
{
sb.AppendLine($"<{defaultNamespace}:{paraName}>{parameters[i]}</{defaultNamespace}:{paraName}>");
}
}
string requestNamespace = soapDocumentAttribute.RequestNamespace;//请求XML命名空间
if (string.IsNullOrWhiteSpace(requestNamespace))
{
requestNamespace = webServiceBindingAttribute.Namespace;
}
string parameterArrayXml = sb.ToString().Trim();
string requestXml = $@"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:{defaultNamespace}=""{requestNamespace}"">
<soapenv:Header/>
<soapenv:Body>
<{defaultNamespace}:{methodName}>{parameterArrayXml}</{defaultNamespace}:{methodName}>
</soapenv:Body>
</soapenv:Envelope>";
//return requestXml;
string formattedXml = XmlSerializeUtil.FormatXml(requestXml);
return formattedXml;
}
}
}
窗体FormGetRequestRawXml主要程序如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GetRequestRawXmlForWebServiceDemo
{
public partial class FormGetRequestRawXml : Form
{
public FormGetRequestRawXml()
{
InitializeComponent();
}
private void btnGetRequestXml_Click(object sender, EventArgs e)
{
rtxtRequestXml.Clear();
try
{
rtxtRequestXml.AppendText("-----------------------第一个请求原生Xml:【中->英】-----------------------\n");
TranslatorWebService.TranslatorWebService translatorWebService = new TranslatorWebService.TranslatorWebService();
translatorWebService.Url = "http://www.webxml.com.cn/WebServices/TranslatorWebService.asmx?wsdl";
translatorWebService.Timeout = 8000;
string word = "中国";
string xml = SoapUtil.GetRawXml<TranslatorWebService.TranslatorWebService>("getEnCnTwoWayTranslator", new object[] { word });
rtxtRequestXml.AppendText(xml);
string[] resultArray = translatorWebService.getEnCnTwoWayTranslator(word);
MessageBox.Show(string.Join("\n", resultArray), "【中->英】翻译结果");
rtxtRequestXml.AppendText("\n\n-----------------------第二个请求原生Xml:【英->中】-----------------------\n\n");
word = "observer";
xml = SoapUtil.GetRawXml<TranslatorWebService.TranslatorWebService>("getEnCnTwoWayTranslator", new object[] { word });
rtxtRequestXml.AppendText(xml);
resultArray = translatorWebService.getEnCnTwoWayTranslator(word);
MessageBox.Show(string.Join("\n", resultArray), "【英->中】翻译结果");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "出错");
}
}
}
}
运行结果如图:
我们可以直接复制请求xml到SoapUI中进行测试,如图: