呼叫Web Service最簡單方式就是在專案中把Web Service參考進來就可以使用。不過,今天要設計一個是可以把Web Service資訊放入資料庫中,系統可以針對不同需求呼叫所需要的Web Serivce的Method並傳入參數,取得對應的值,大致架構如下:
這樣好處在於當Web Service是其他單位設計時候,其他同仁可以專注在Web Service開發,開發完畢後將相關資訊註冊到,資料庫中這樣系統就可以動態取得Web Service並呼叫。
註冊該Web Service時,只需要幾個Info就可以
- Web Service Address
- Web Service Name
- Web Server Method及該Method對應的參數值
實作此方式需要先實踐幾個動作
- 取得該Web Service的WSDL描述
- 讀取該Web Service WSDL內的XML描述
- 產生對應Web Service Proxy並動態編譯為Assembly呼叫會使用到的Namespace
會使用的Namespace
需要語言編譯Assembly的語言,設定為C#
1using Microsoft.CSharp;動態原始程式碼的產生和編譯
12using System.CodeDom;using System.CodeDom.Compiler;取得Web 服務描述語言
WSDL
,透過機制可以讓我們動態取用Web Service及其Method跟輸入參數1using System.Web.Services.Description;
產生Client Proxy 類別
要了解整個Web Service內的Method及操作相關資訊,最重要的部分就是要先了解其服務描述,因此透過服務描述就可以開始操作相關Service動作服務描述範例會示範服務如何在執行階段擷取其服務描述資訊。此範例是以使用者入門範例為基礎,同時包含已定義可傳回有關服務之描述資訊的其他服務作業。傳回的資訊會列出服務的基底位址與端點。服務會使用OperationContext
、ServiceHost
和ServiceDescription
類別提供這項資訊。
取得Web Service的WSDL描述的XML字串,其中
_UriAddress
為Web Service的Address1XmlTextReader XTR = new XmlTextReader(_UriAddress.ToString() + "?WSDL")讀取到Web Service的WSDL內容轉成用戶端的Proxy類別,這樣才有辦法供自己進行呼叫。要將WSDL轉成Proxy,Assembly則用
ServiceDescriptionImporter
類別1ServiceDescriptionImporter drimport = GetWSDLProxy(XTR);將
XmlTextReader
讀到的xml字串轉換為具有適當命名空間、項目和屬性的有效Web服務描述語言WSDL
文件,ServiceDescription
類別使用new關鍵字或靜態Read方法加以建立,該方法會剖析WSDL
,並將它的值指派至適當的類別成員123456if(!ServiceDescription.CanRead(_XTR)){throw new Exception("WSDL的Description錯誤");}//取得WSDL內容ServiceDescription Description = ServiceDescription.Read(_XTR);- 透過CanRead先判斷XML格式是否可以有效解析
- Read 方法加以建立物件
產生用戶端的Web Service Proxy
1ServiceDescriptionImporter oProxy = new ServiceDescriptionImporter();設定
ProtocoName
屬性1oProxy.ProtocolName = "SOAP";設定其他屬性
123oProxy.AddServiceDescription(Description, null, null);//Style選擇ClientoProxy.Style = ServiceDescriptionImportStyle.Client;定義XML基礎型別
1oProxy.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
這樣就可以取得該Web Service的WSDL並且產生Web Service Proxy的類別,後續再將將此類別編譯成Assembly供系統使用
完整程式碼
即時編譯Proxy Class
需要再將類別透過C#編譯為Assembly,供內部程式作為使用。欲做到這樣動作,需要用CodeNamespace
& CodeCompileUnit
兩個類別。以上兩個類別都是屬於System.CodeDom
NameSpace
CodeCompileUnit & CodeNamespace 類別
12CodeNamespace oCodeNamespace = new CodeNamespace();CodeCompileUnit oCodeCompileUnit = new CodeCompileUnit();新增一個命名空間
1oCodeCompileUnit.Namespaces.Add(oCodeNamespace);匯入指定的 ServiceDescriptions 值並產生警告型別的物件
1ServiceDescriptionImportWarnings Warning = _sim.Import(oCodeNamespace, oCodeCompileUnit);因為是要編譯是Web Service及XML的Assembly的物件,所以,需要相關性的dll協助我們做這些事情,因此,在後面的編譯器,需要參考到
System.Web.Services.dll
和System.Xml.dll
1string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };給定編譯器所需要的參數
1CompilerParameters parameters = new CompilerParameters(references);回傳編譯的結果,因為是要編譯成C#,所以,需要再額外參考
Microsoft.CSharp
Namespace,這樣才可以提供CSharpCodeProvider作為編譯器,這樣可以把CodeCompileUnit
物件之指定陣列所包含的System.CodeDom
樹狀結構,編譯一個組件1CompilerResults results = new CSharpCodeProvider().CompileAssemblyFromDom(parameters, oCodeCompileUnit);
若是使用CompileAssemblyFromFile
,將可以指定檔案所包含的原始程式碼中編譯組件
- 最後回傳Assembly12345foreach (CompilerError oops in results.Errors){throw new Exception("Compilation Error Creating Assembly");}return results.CompiledAssembly;
完整程式碼