C#动态调用WebService的两种方法:封装类与HTTP直接请求

Dylan
Dylan
发布时间:2026-10-14 | 6人浏览过
原创

本文详细解析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协议解析的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表