C#动态调用WebService的两种方法:封装类与HTTP直接请求
本文详细解析C#中动态调用WebService的两个典型场景与实现代码:第一种是基于通用辅助类WebServicesHelper处理标准SOAP信封及命名空间缓存;第二种是利用HttpWebRequest进行原生HTTP通信,通过构建完整的soapenv:Envelope XML字符串并配合异步回调获取结果。内容涵盖参数序列化、命名空间自动检测及网络流处理。
方法一:基于辅助类的SOAP动态封装
此方法适用于需要频繁调用不同接口且希望统一处理逻辑的场景。核心在于使用WebServicesHelper.QuerySoapWebService工具方法,它会自动将传入的Hashtable参数序列化为SOAP协议所需的XML结构,并通过HttpWebRequest执行POST操作。
第1步:准备调用环境与数据
首先需要实例化一个Hashtable用于存放接口所需的键值对参数,明确目标URL和具体MethodName。例如:
Hashtable ht = new Hashtable();
ht.Add("a", "testhelloworld");
// 假设存在自定义辅助类 WebServicesHelper
XmlDocument xx = WebServicesHelper.QuerySoapWebService(
"https://www.jb51.net/elab_mgmt/WorkflowSchemeTaskSerivce.asmx",
"ATesting",
ht);
string ss = xx.OuterXml;
第2步:解析命名空间与缓存管理
QuerySoapWebService内部会根据URL检索对应的Namespace(命名空间)。为了提升效率,它会优先检查私有字典_xmlNamespaces的缓存:
public static XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars)
{
if (_xmlNamespaces.ContainsKey(URL))
{
return QuerySoapWebService(URL, MethodName, Pars, _xmlNamespaces[URL].ToString());
}
else
{
// 若不存在缓存,则调用 GetNamespace 实时抓取 WSDL 中的命名空间
return QuerySoapWebService(URL, MethodName, Pars, GetNamespace(URL));
}
}
该方法通过访问 {URL}?WSDL 链接来获取目标服务的精确命名空间,这对于构造正确的SOAPAction头至关重要。
第3步:组装并发送HTTP请求
底层实现使用HttpWebRequest建立连接。关键配置步骤如下:
- 设定动作:
request.Method = "POST" - 指定类型:
request.ContentType = "text/xml; charset=utf-8" - 注入Header:拼接命名空间与方法名生成SOAPAction,如
"http://tempuri.org/Method" - 写入Body:通过
EncodeParsToSoap将哈希表转换为XML字节流。
private static XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars, string XmlNs)
{
_xmlNamespaces[URL] = XmlNs; // 加入缓存
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "text/xml; charset=utf-8";
request.Headers.Add("SOAPAction", "\"" + XmlNs + (XmlNs.EndsWith("/") ? "" : "/") + MethodName + "\"");
SetWebRequest(request);
byte[] data = EncodeParsToSoap(Pars, XmlNs, MethodName);
WriteRequestData(request, data);
// ...读取响应逻辑...
第4步:解析返回结果
接收响应后,使用XmlNamespaceManager注册SOAP标准命名空间前缀,提取Body内的真实数据:
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
String RetXml = doc.SelectSingleNode("//soap:Body/*/*", mgr).InnerXml;
最后将结果包裹为根节点<root></root>以返回标准的XmlDocument对象。
附录:获取动态命名空间的实现
当无法预先确定服务Namespace时,可通过下载WSDL文件自动提取:
private static string GetNamespace(String URL)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL + "?WSDL");
SetWebRequest(request);
WebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sr.ReadToEnd());
sr.Close();
return doc.SelectSingleNode("//@targetNamespace").Value;
}
方法二:基于HTTP异步请求的直接SOAP调用
第二种方式更贴近底层网络通信。通常通过SOURCE UI等工具录制生成的完整SOAP XML报文作为基础模板,直接在C#中使用System.Net.HttpWebRequest进行异步(Async)POST操作,适合高并发或对框架依赖度较低的需求。
第1步:构造SOAP请求体
根据WSDL格式手动拼装XML字符串,确保命名空间(xmlns)和方法内标签完全匹配:
string postData2 = @"<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/"> <soapenv:Header/>
<soapenv:Body>
<tem:ATesting>
<!--Optional:-->
<tem:a>TestValue</tem:a>
</tem:ATesting>
</soapenv:Body>
</soapenv:Envelope>";
第2步:发起异步HTTP POST请求
此处演示了如何使用类似HttpHelper.GetResponseFormUrlAsync的方法发起非阻塞请求。关键点在于绑定回调函数responseCallback并在完成后处理业务逻辑:
// 伪代码展示异步调用入口
HttpHelper.GetResponseFormUrlAsync(
"http://www.xxx.com/testingservices.asmx",
postData2,
"text/xml",
true,
new AsyncCallback(responseCallback));
第3步:在回调中处理响应与异常
在responseCallback(IAsyncResult ar)中,需要安全地获取原始请求对象,并验证状态码。以下是处理流程的代码骨架:
static void responseCallback(IAsyncResult ar)
{
HttpWebRequest req = ar.AsyncState as HttpWebRequest;
if (req == null) return;
try
{
using (HttpWebResponse response = req.EndGetResponse(ar) as HttpWebResponse)
{
// 1. 检查 HTTP 状态是否为 200 OK
if (response.StatusCode != HttpStatusCode.OK)
{
// LogHelper.Error(...);
return;
}
// 2. 读取流数据
Stream responseStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8))
{
string ResponseStr = reader.ReadToEnd();
// 此时可获得返回的 SOAP XML 文本
LogHelper.Warn("Result", ResponseStr);
}
}
}
catch (Exception e)
{
// 捕获网络中断、超时等系统异常
LogHelper.Fatal("Execution Failed", e);
}
}
总结对比
| 特性 | 方法一 (封装类模式) | 方法二 (异步HTTP模式) |
|---|---|---|
| 复杂度 | 中等,高度封装,适合快速集成 | 偏高,需手动维护XML结构和流处理 |
| 参数传递 | 支持弱类型Hashtable自动转XML | 必须提供完整的硬编码XML报文 |
| 性能 | 包含反射与XML树解析开销 | 纯I/O流操作,相对更轻量(针对特定请求) |
| 适用场景 | 多接口统一管理、动态切换服务 | 固定接口的高频异步调用、微服务间通信 |
以上就是关于C#动态调用Webservice的两种方法(辅助类封装与原生HTTP请求)的详细内容。更多关于.NET高级网络编程及SOAP协议解析的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













