我們都知道,調用WebService可以在工程中對WebService地址進行WEB引用,但是這確實很不方便。我想能夠利用配置文件靈活調用WebService。如何實現呢?
用C#通過反射實現動態調用WebService
上代碼,先試再說:
using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO; using System.Web.Services.Description; using System.CodeDom; using Microsoft.CSharp; using System.CodeDom.Compiler; namespace TestCommon { public class Webservice { /// <summary> /// 實例化WebServices /// </summary> /// <param name="url">WebServices地址</param> /// <param name="methodname">調用的方法</param> /// <param name="args">把webservices里需要的參數按順序放到這個object[]里</param> public static object InvokeWebService(string url, string methodname, object[] args) { //這里的namespace是需引用的webservices的命名空間,我沒有改過,也可以使用。也可以加一個參數從外面傳進來。 string @namespace = "client"; try { //獲取WSDL WebClient wc = new WebClient(); Stream stream = wc.OpenRead(url + "?WSDL"); ServiceDescription sd = ServiceDescription.Read(stream); string classname = sd.Services[0].Name; ServiceDescriptionImporter sdi = new ServiceDescriptionImporter(); sdi.AddServiceDescription(sd, "", ""); CodeNamespace cn = new CodeNamespace(@namespace); //生成客戶端代理類代碼 CodeCompileUnit ccu = new CodeCompileUnit(); ccu.Namespaces.Add(cn); sdi.Import(cn, ccu); CSharpCodeProvider csc = new CSharpCodeProvider(); //ICodeCompiler icc = csc.CreateCompiler(); //設定編譯參數 CompilerParameters cplist = new CompilerParameters(); cplist.GenerateExecutable = false; cplist.GenerateInMemory = true; cplist.ReferencedAssemblies.Add("System.dll"); cplist.ReferencedAssemblies.Add("System.XML.dll"); cplist.ReferencedAssemblies.Add("System.Web.Services.dll"); cplist.ReferencedAssemblies.Add("System.Data.dll"); //編譯代理類 CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu); if (true == cr.Errors.HasErrors) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors) { sb.Append(ce.ToString()); sb.Append(System.Environment.NewLine); } throw new Exception(sb.ToString()); } //生成代理實例,並調用方法 System.Reflection.Assembly assembly = cr.CompiledAssembly; Type t = assembly.GetType(@namespace + "." + classname, true, true); object obj = Activator.CreateInstance(t); System.Reflection.MethodInfo mi = t.GetMethod(methodname); return mi.Invoke(obj, args); } catch { return null; } } } }
注意:上述代碼需要引用如下四個名稱空間:
using System.Web.Services.Description; //WS的描述
//以下幾個用於根據描述動態生成代碼並動態編譯獲取程序集
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
如果你看到這段文字,說明您正使用RSS閱讀或轉自《一棵樹-博客園》,原文地址:http://www.cnblogs.com/atree/p/WebService_dynamic.html
代碼相對簡單,為什么可以如此調用呢?動態編譯后用反射來讀取並執行。也許了解反射及如何反射對你會有幫助。
反射提供了封裝程序集、模塊和類型的對象(Type 類型)。可以使用反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型並調用其方法或訪問其字段和屬性。詳細請查看:https://msdn.microsoft.com/zh-cn/library/ms173183(VS.80).aspx
為什么WebServices可以通過反射實現?
WebService在傳輸過程中是通過WSDL來進行描述的(使用SOAP協議)。因此,我們需要獲取WebService的WSDL描述,並通過該描述來動態生成程序集。然后通過反射來獲取新生成的程序集,並調用其方法!
以下是MSDN對其的描述:
XML Web services 的接口通常由 Web 服務描述語言 (WSDL) 文件來說明。例如,若要獲取有關使用
http://localhost/service.asmx
處公開的 ASP.NET 的 Web 服務的 WSDL 說明,只需導航到http://localhost/service.asmx?WSDL
。使用 ServiceDescriptionImporter 類可以方便地將 WSDL 說明中包含的信息導入到System.CodeDom.CodeCompileUnit 對象。通過調整 Style 參數的值,可以指示 ServiceDescriptionImporter 實例生成客戶端代理類(通過透明調用該類可提供 Web 服務的功能)或生成抽象類(該類封裝 Web 服務的功能而不實現該功能)。如果將 Style 屬性設置為 Client,則 ServiceDescriptionImporter 生成客戶端代理類,通過調用這些類來提供說明的 Web 服務的功能。如果將 Style 屬性設置為 Server,則 ServiceDescriptionImporter 實例生成抽象類,這些類表示所說明的 XML Web services 的功能而不進行實現。然后,可以通過編寫從這些抽象類繼承的類來對其進行實現,並實現相關的方法。
了解更多關於WebServices的知識:
MSDN:https://msdn.microsoft.com/zh-cn/library/system.web.services.webservice(VS.80).aspx