我們都知道,調用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
