首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C# 動態呼叫 WebService 完整實作指南:免加入 Web 參考

     編輯:更多程式設計知識

在企業級應用開發中,WebService 呼叫通常透過 Visual Studio「加入服務參考」產生靜態 Proxy 類別。但當服務端點頻繁變動、或需在執行期動態決定呼叫哪個服務時,靜態參考顯得不夠彈性。本文介紹如何使用 HttpWebRequest 與 ServiceDescriptionImporter 實現完全動態的 WebService 呼叫,支援 SOAP、HTTP GET/POST 多種協定。

核心優勢

  • 零靜態參考:專案無需加入 Web Reference,部署時只需修改設定檔中的 WSDL 網址。
  • 多協定支援:同一套元件可呼叫 SOAP、HTTP GET、HTTP POST 三種模式。
  • 效能優化:內建命名空間快取機制,避免重複下載 WSDL 解析。

方案一:輕量級 HttpWebRequest 實作(適用簡單 SOAP 呼叫)

以下為核心類別 WebServiceCaller,封裝了三種呼叫方式:

HTTP POST 呼叫

public static XmlDocument QueryPostWebService(string url, string methodName, Hashtable pars)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "/" + methodName);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    SetRequest(request);
    byte[] data = EncodePars(pars);
    WriteRequestData(request, data);
    return ReadXmlResponse(request.GetResponse());
}

HTTP GET 呼叫

public static XmlDocument QueryGetWebService(string url, string methodName, Hashtable pars)
{
    string queryString = ParsToString(pars);
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"{url}/{methodName}?{queryString}");
    request.Method = "GET";
    request.ContentType = "application/x-www-form-urlencoded";
    SetRequest(request);
    return ReadXmlResponse(request.GetResponse());
}

SOAP 協定呼叫(核心)

public static XmlDocument QuerySoapWebService(string url, string methodName, Hashtable pars)
{
    string xmlNs = _xmlNamespaces.ContainsKey(url) 
        ? _xmlNamespaces[url].ToString() 
        : GetNamespace(url); // 快取命名空間

    return QuerySoapWebService(url, methodName, pars, xmlNs);
}

private static XmlDocument QuerySoapWebService(string url, string methodName, Hashtable pars, string xmlNs)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "text/xml; charset=utf-8";
    request.Headers.Add("SOAPAction", $"\"{xmlNs}{(xmlNs.EndsWith("/") ? "" : "/")}{methodName}\"");
    SetRequest(request);

    byte[] soapData = EncodeParsToSoap(pars, xmlNs, methodName);
    WriteRequestData(request, soapData);

    XmlDocument doc = ReadXmlResponse(request.GetResponse());
    
    // 擷取 SOAP Body 實際回傳內容
    XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
    mgr.AddNamespace("soap", "https://schemas.xmlsoap.org/soap/envelope/");
    string retXml = doc.SelectSingleNode("//soap:Body/*/*", mgr).InnerXml;
    
    XmlDocument result = new XmlDocument();
    result.LoadXml("<root>" + retXml + "</root>");
    AddDeclaration(result);
    return result;
}

關鍵輔助方法

  • GetNamespace(url):下載 WSDL 並解析 targetNamespace。
  • EncodeParsToSoap():將 Hashtable 參數序列化為 SOAP XML 訊息。
  • ObjectToSoapXml():使用 XmlSerializer 處理複雜型別參數。

方案二:Runtime 產生 Proxy 組件(適用複雜型別、強型別需求)

當 WebService 涉及複雜資料結構(如 DataSet、自訂類別),手工組裝 SOAP 訊息極易出錯。進階做法是執行期下載 WSDL,使用 CodeDom 動態編譯產生 Proxy DLL,再透過 Reflection 呼叫。

核心流程

  1. WebClient 下載 WSDL 內容。
  2. ServiceDescriptionImporter 產生客戶端 Proxy 程式碼。
  3. CodeDomProvider 編譯為記憶體或暫存檔 DLL。
  4. Assembly.LoadFrom 載入組件,Activator.CreateInstance 建立 Proxy 實例。
  5. MethodInfo.Invoke 動態呼叫目標方法。

關鍵程式碼片段

// 快取機制:依 WSDL 內容 MD5 命名 DLL,避免重複編譯
string assPath = Path.GetTempPath() + assName + GetMd5Sum(wsdlUrl) + ".dll";

if (File.Exists(assPath)) // 快取命中
{
    InitTypeName();
    return;
}

// 編譯參數設定
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.AddRange(new[] { "System.dll", "System.Xml.dll", "System.Web.Services.dll", "System.Data.dll" });
cp.GenerateInMemory = false; // 必須產生實體檔案才能 LoadFrom
cp.OutputAssembly = assPath;

CompilerResults cr = provider.CompileAssemblyFromDom(cp, unit);
if (cr.Errors.HasErrors) throw new Exception("動態編譯失敗:" + cr.Errors[0].ErrorText);

File.Copy(cr.PathToAssembly, assPath, true); // 複製到快取路徑
InitTypeName(); // 反射取得 Proxy 類別 Type

呼叫範例

// 方案一:簡單 SOAP 呼叫
Hashtable ht = new Hashtable();
ht.Add("xmlIn", "<Request><MemCode>001</MemCode></Request>");
XmlDocument result = WebServiceCaller.QuerySoapWebService(
    "https://example.com/Service.asmx", "SinPointQuery", ht);

// 方案二:強型別 Proxy 呼叫
WebServiceProxy proxy = new WebServiceProxy("https://localhost:8080/Service?wsdl", "MyService");
object[] args = new object[] { "參數1", "參數2" };
string ret = (string)proxy.ExecuteQuery("MethodName", args);

部署與維護建議

  • 將 WSDL URL 放入 appSettings 或資料庫,上線時只需修改設定值。
  • SOAP 呼叫需確認伺服器 web.config 已啟用 <protocols> 中的 HttpGet、HttpPost、HttpSoap。
  • 動態編譯方案需注意目標機器擁有 .NET Framework SDK(含 csc.exe),或預先在建置伺服器編譯好 Proxy DLL 隨部署包釋出。

動態 WebService 呼叫技術讓系統具備極高彈性,特別適合多租戶、微服務閘道、或第三方整合平台等情境。根據專案複雜度選擇輕量級 HttpWebRequest 或完整 Proxy 編譯方案,皆能有效解決靜態參考的維護痛點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved