动态调用WebService(C#) (非常实用)
通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却和提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果哪一天发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。在某些情况下,这可能是不能忍受的,我们需要动态调用WebService的能力。比如我们可以把Web服务的URL保存在配置文件中,这样,当服务URL改变时,只需要修改配置文件就可以了。
说了这么多,实际上我们要实现这样的功能:
- public static object InvokeWebService(string url, string methodname, object[] args)
- public static object InvokeWebService(string url, string methodname, object[] args)
其中,url是Web服务的地址,methodname是要调用服务方法名,args是要调用Web服务所需的参数,返回值就是web服务返回的结果了。
要实现这样的功能,你需要这几个方面的技能:反射、CodeDom、编程使用C#编译器、WebService。在了解这些知识后,就可以容易的实现web服务的动态调用了:
- #region InvokeWebService
- //动态调用web服务
- public static object InvokeWebService(string url, string methodname, object[] args)
- {
- return WebServiceHelper.InvokeWebService(url ,null ,methodname ,args) ;
- }
- public static object InvokeWebService(string url, string classname, string methodname, object[] args)
- {
- string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;
- if((classname == null) ||(classname == ""))
- {
- classname = WebServiceHelper.GetWsClassName(url) ;
- }
- try
- {
- //获取WSDL
- WebClient wc = new WebClient();
- Stream stream = wc.OpenRead(url+"?WSDL");
- ServiceDescription sd = ServiceDescription.Read(stream);
- 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 = icc.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(Exception ex)
- {
- throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
- }
- }
- private static string GetWsClassName(string wsUrl)
- {
- string[] parts = wsUrl.Split('/') ;
- string[] pps = parts[parts.Length-1].Split('.') ;
- return pps[0] ;
- }
- #endregion
- #region InvokeWebService
- //动态调用web服务
- public static object InvokeWebService(string url, string methodname, object[] args)
- {
- return WebServiceHelper.InvokeWebService(url ,null ,methodname ,args) ;
- }
- public static object InvokeWebService(string url, string classname, string methodname, object[] args)
- {
- string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;
- if((classname == null) ||(classname == ""))
- {
- classname = WebServiceHelper.GetWsClassName(url) ;
- }
- try
- {
- //获取WSDL
- WebClient wc = new WebClient();
- Stream stream = wc.OpenRead(url+"?WSDL");
- ServiceDescription sd = ServiceDescription.Read(stream);
- 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 = icc.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(Exception ex)
- {
- throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
- }
- }
- private static string GetWsClassName(string wsUrl)
- {
- string[] parts = wsUrl.Split('/') ;
- string[] pps = parts[parts.Length-1].Split('.') ;
- return pps[0] ;
- }
- #endregion
上面的注释已经很好的说明了各代码段的功能,下面给个例子看看,这个例子是通过访问http://www.webservicex.net/globalweather.asmx 服务来获取各大城市的天气状况。
- string url = "http://www.webservicex.net/globalweather.asmx" ;
- string[] args = new string[2] ;
- args[0] = this.textBox_CityName.Text ;
- args[1] = "China" ;
- object result = WebServiceHelper.InvokeWebService(url ,"GetWeather" ,args) ;
- this.label_Result.Text = result.ToString() ;
- string url = "http://www.webservicex.net/globalweather.asmx" ;
- string[] args = new string[2] ;
- args[0] = this.textBox_CityName.Text ;
- args[1] = "China" ;
- object result = WebServiceHelper.InvokeWebService(url ,"GetWeather" ,args) ;
- this.label_Result.Text = result.ToString() ;
上述的例子中,调用web服务使用了两个参数,第一个是城市的名字,第二个是国家的名字,Web服务返回的是XML文档,可以从其中解析出温度、风力等天气情况。
最后说一下,C#虽然仍属于静态语言之列,但是其动态能力也是很强大的,不信,你可以看看Spring.net的AOP实现,这种“无侵入”的AOP实现比通常的.NET声明式AOP实现(一般是通过AOP
Attribute)要漂亮的多。
c#动态调用WebService
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.Net;
- using System.Web.Services.Description;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.Reflection;
- namespace WindowsServiceWebDefaultHotCity
- {
- /// <summary<
- /// WebService代理类
- /// </summary<
- public class WebServiceAgent
- {
- private object agent;
- private Type agentType;
- private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
- /// <summary<
- /// 构造函数
- /// </summary<
- /// <param name="url"<</param<
- public WebServiceAgent(string url)
- {
- XmlTextReader reader = new XmlTextReader(url + "?wsdl");
- //创建和格式化 WSDL 文档
- ServiceDescription sd = ServiceDescription.Read(reader);
- //创建客户端代理代理类
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.AddServiceDescription(sd, null, null);
- //使用 CodeDom 编译客户端代理类
- CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();
- CompilerParameters cp = new CompilerParameters();
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- agentType = cr.CompiledAssembly.GetTypes()[0];
- agent = Activator.CreateInstance(agentType);
- }
- ///<summary<
- ///调用指定的方法
- ///</summary<
- ///<param name="methodName"<方法名,大小写敏感</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(string methodName, params object[] args)
- {
- MethodInfo mi = agentType.GetMethod(methodName);
- return this.Invoke(mi, args);
- }
- ///<summary<
- ///调用指定方法
- ///</summary<
- ///<param name="method"<方法信息</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(MethodInfo method, params object[] args)
- {
- return method.Invoke(agent, args);
- }
- public MethodInfo[] Methods
- {
- get
- {
- return agentType.GetMethods();
- }
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.Net;
- using System.Web.Services.Description;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.Reflection;
- namespace WindowsServiceWebDefaultHotCity
- {
- /// <summary<
- /// WebService代理类
- /// </summary<
- public class WebServiceAgent
- {
- private object agent;
- private Type agentType;
- private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
- /// <summary<
- /// 构造函数
- /// </summary<
- /// <param name="url"<</param<
- public WebServiceAgent(string url)
- {
- XmlTextReader reader = new XmlTextReader(url + "?wsdl");
- //创建和格式化 WSDL 文档
- ServiceDescription sd = ServiceDescription.Read(reader);
- //创建客户端代理代理类
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.AddServiceDescription(sd, null, null);
- //使用 CodeDom 编译客户端代理类
- CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();
- CompilerParameters cp = new CompilerParameters();
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- agentType = cr.CompiledAssembly.GetTypes()[0];
- agent = Activator.CreateInstance(agentType);
- }
- ///<summary<
- ///调用指定的方法
- ///</summary<
- ///<param name="methodName"<方法名,大小写敏感</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(string methodName, params object[] args)
- {
- MethodInfo mi = agentType.GetMethod(methodName);
- return this.Invoke(mi, args);
- }
- ///<summary<
- ///调用指定方法
- ///</summary<
- ///<param name="method"<方法信息</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(MethodInfo method, params object[] args)
- {
- return method.Invoke(agent, args);
- }
- public MethodInfo[] Methods
- {
- get
- {
- return agentType.GetMethods();
- }
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- namespace WindowsApplication1
- {
- public partial class Form1 : Form
- {
- private string _url = "http://www.baidu.com";
- public Form1()
- {
- InitializeComponent();
- init_Data();
- }
- public void init_Data()
- {
- WindowsServiceWebDefaultHotCity.WebServiceAgent agent = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
- object[] args = new object[6];
- args[0] = "PEK";
- args[1] = "CAN";
- args[2] = "";
- args[3] = "2008-08-02";
- args[4] = "00:00";
- args[5] = "own_9588";
- string text=agent.Invoke("GetAllFlight", args).ToString();
- textBox1.Text = text;
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- namespace WindowsApplication1
- {
- public partial class Form1 : Form
- {
- private string _url = "http://www.baidu.com";
- public Form1()
- {
- InitializeComponent();
- init_Data();
- }
- public void init_Data()
- {
- WindowsServiceWebDefaultHotCity.WebServiceAgent agent = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
- object[] args = new object[6];
- args[0] = "PEK";
- args[1] = "CAN";
- args[2] = "";
- args[3] = "2008-08-02";
- args[4] = "00:00";
- args[5] = "own_9588";
- string text=agent.Invoke("GetAllFlight", args).ToString();
- textBox1.Text = text;
- }
- }
- }
- 我们都知道,调用WS可以在工程中添加对WS的WEB引用。
- 但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢?
- 首先,我们该想到WS的实现也是一个类的形式。
- 其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。
- 因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。
- 最后:通过反射来获取新生成的程序集,并调用其方法!
- 上述步骤需要引用如下四个名称空间:
- using System.Web.Services.Description; //WS的描述
- //以下几个用于根据描述动态生成代码并动态编译获取程序集
- using System.CodeDom;
- using Microsoft.CSharp;
- using System.CodeDom.Compiler;
- 上述几个名称空间中包括如下几个重要的类:
- using System.Web.Services.Description下:
- ServiceDescription //WS描述
- ServiceDescriptionImporter //通过描述生成客户端代理类,特别注意其中的Style
- 以下是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 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
- using System.CodeDom下:
- CodedomUnit //它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WS的描述代码写入该类,以作动态编译用
- 我们都知道,调用WS可以在工程中添加对WS的WEB引用。
- 但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢?
- 首先,我们该想到WS的实现也是一个类的形式。
- 其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。
- 因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。
- 最后:通过反射来获取新生成的程序集,并调用其方法!
- 上述步骤需要引用如下四个名称空间:
- using System.Web.Services.Description; //WS的描述
- //以下几个用于根据描述动态生成代码并动态编译获取程序集
- using System.CodeDom;
- using Microsoft.CSharp;
- using System.CodeDom.Compiler;
- 上述几个名称空间中包括如下几个重要的类:
- using System.Web.Services.Description下:
- ServiceDescription //WS描述
- ServiceDescriptionImporter //通过描述生成客户端代理类,特别注意其中的Style
- 以下是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 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
- using System.CodeDom下:
- CodedomUnit //它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WS的描述代码写入该类,以作动态编译用
using System.CodeDom.Compiler下:
CodedomProvider
//用于创建和检索代码生成器和代码编译器的实例,我们主要用到其实现子类CShareCodeProvider
可以直接用CShareCodeProvider
provider=new
CShareCodeProvider()来生成,或者用CodedomProvider.CreateProvider("CSharp")来生成
ICodeCompiler
//用于编译基于 System.CodeDom
的源代码表示形式。
它通过CodedomProvider的CreateCompiler()方法来
CompilerResults
//表示从编译器返回的编译结果。 它由ICodeCompiler根据指定的编译器设置从指定的 CodeCompileUnit 所包含的
System.CodeDom 树中编译程序集并返回。CompiledAssembly 属性指示编译的程序集。
了解如上信息后,就可动态调用WS了。
如下是摘自http://www.cnblogs.com/ruochen/archive/2007/12/11/990427.html的代码演示:
Code
该方法可以使程序不通过web引用的方式去调用webservices方法,直接在代码里调用该方法就能达到动态调用webservices的目的。使用前先引用System.Web.Services动态链接库,是.net自带的dll。
方法如下:
- 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 TestSkin
- {
- class Webservices
- {
- /// <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 = icc.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;
- 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 TestSkin
- {
- class Webservices
- {
- /// <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 = icc.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;
- }
- }
- }
- }
===了解上述类和方法后,基本就可以动态调用WS了。
特别注意的是:动态编译后需要用到反射来读取并执行。因此需要您了解什么是反射及如何反射。
web
service的动态调用,主要有三种方法。
1、修改config文件。只要你引用了web
service,就会在config文件中出现asmx文件的地址。只需要修改该地址即可。
2、程序修改url。web
service是集成了System.Web.Service.WebService类的,而该类有一个Url属性。通过修改该属性可以达到与方法一一样的效果,并且比它还要灵活。有的时候,我们需要提供一个列表,有很多的服务器让用户选择。程序根据用户的选择连接到不同的服务器上调用web
service。这时,就可以用这个方法了。
3、接口引用。有的时候,我们需要调用不同服务器上的web
service,但他们彼此又不一样,只是都实现了同一个接口。这时候,就可以考虑下面的这个方法。只要先引用所有的web
service,然后用接口实例来保存创建出来的web
service对象即可。
4、动态编译。这个应该算得上是真正意义上的动态了。有的时候,各个服务器上的web
service更新比较快,我们不可能天天去更新代理类的,这个时候就可以用这个方法了。
在该方法中,有一点限制。就是各个服务器的web
service,要么是都继承了同一个接口,要么是都有一些同样签名的方法,而且service的类名最好是一样的。不过就算不符合这条件也没关系,后面我会在注释中注明的。看代码:
- using System;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.IO;
- using System.Net;
- using System.Reflection;
- using System.Web.Services.Description;
- using Microsoft.CSharp;
- //获取Web Service描述
- WebClient wc= new WebClient();
- Stream stream = wc.OpenRead("http://localhost/TestService.asmx?WSDL"); //这里指定你自己的web service url,一定要以?WSDL结尾
- ServiceDescription sd = ServiceDescription.Read(stream);
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.ProtocolName = "soap";
- sdi.Style = ServiceDescriptionImportStyle.Client;
- sdi.AddServiceDescription(sd, null, null);
- //指定命名空间
- CodeNamespace cn = new CodeNamespace("Test"); //这里随便指定一个命名空间,但要与后面的一致
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- 建立C#编译器
- CSharpCodeProvider csc = new CSharpCodeProvider();
- ICodeCompiler icc = csc.CreateCompiler();
- CompilerParameters cp = new CompilerParameters();
- cp.GenerateExecutable = false;
- cp.GenerateInMemory = true;
- //添加编译条件
- cp.ReferencedAssemblies.Add("System.dll");
- cp.ReferencedAssemblies.Add("System.XML.dll");
- cp.ReferencedAssemblies.Add("System.Web.Services.dll");
- //编译程序集
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- //检查是否编译成功
- if (!cr.Errors.HasErrors)
- {
- //编译成功
- //获取程序集
- Assembly assembly = cr.CompiledAssembly;
- //获取程序集类型
- //前面的Test就是命名空间,必须要与前面指定的一致
- //后面的TestService就是service的类名
- //如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名
- Type type = assembly.GetType("Test.TestService", true);
- object service = Activator.CreateInstance(type);
- //获取方法
- //如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名
- MethodInfo mi = type.GetMethod("HelloWorld");
- //调用方法
- //如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致
- //如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序
- mi.Invoke(service, null);
- //最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。
- }
- else
- {
- //这里自己处理编译错误
- }
- using System;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.IO;
- using System.Net;
- using System.Reflection;
- using System.Web.Services.Description;
- using Microsoft.CSharp;
- //获取Web Service描述
- WebClient wc= new WebClient();
- Stream stream = wc.OpenRead("http://localhost/TestService.asmx?WSDL"); //这里指定你自己的web service url,一定要以?WSDL结尾
- ServiceDescription sd = ServiceDescription.Read(stream);
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.ProtocolName = "soap";
- sdi.Style = ServiceDescriptionImportStyle.Client;
- sdi.AddServiceDescription(sd, null, null);
- //指定命名空间
- CodeNamespace cn = new CodeNamespace("Test"); //这里随便指定一个命名空间,但要与后面的一致
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- 建立C#编译器
- CSharpCodeProvider csc = new CSharpCodeProvider();
- ICodeCompiler icc = csc.CreateCompiler();
- CompilerParameters cp = new CompilerParameters();
- cp.GenerateExecutable = false;
- cp.GenerateInMemory = true;
- //添加编译条件
- cp.ReferencedAssemblies.Add("System.dll");
- cp.ReferencedAssemblies.Add("System.XML.dll");
- cp.ReferencedAssemblies.Add("System.Web.Services.dll");
- //编译程序集
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- //检查是否编译成功
- if (!cr.Errors.HasErrors)
- {
- //编译成功
- //获取程序集
- Assembly assembly = cr.CompiledAssembly;
- //获取程序集类型
- //前面的Test就是命名空间,必须要与前面指定的一致
- //后面的TestService就是service的类名
- //如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名
- Type type = assembly.GetType("Test.TestService", true);
- object service = Activator.CreateInstance(type);
- //获取方法
- //如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名
- MethodInfo mi = type.GetMethod("HelloWorld");
- //调用方法
- //如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致
- //如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序
- mi.Invoke(service, null);
- //最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。
- }
- else
- {
- //这里自己处理编译错误
- }
动态调用WebService(C#) (非常实用)的更多相关文章
- Asp.net动态调用WebService
Public Class WebServiceHelper #Region "InvokeWebService" '动态调用web服务 Public Shared Function ...
- Atitit 动态调用webservice与客户端代理方式调用
Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke 直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...
- 动态调用webservice(部分转载)
动态调用webservice,做个笔记: public class WSHelper { /// < summary> /// 动态调用web服务 /// < /summary> ...
- C# 动态调用webservice
最近项目中,用到动态调用webservice的内容,此处记录下来,留着以后COPY(我们只需要在XML,config文件,或者数据库中配置webservice连接地址和方法名即可使用): using ...
- 动态调用webservice及WCF服务
动态调用web服务,该方法只针对Web service, WCF的服务不行,如果是WCF的就通过工具直接生产代理类,把代理类配置到调用的项目中,通过配置客户端的终结点动态的取实现: 通过Svcutil ...
- C# .NET 动态调用webservice的三种方式
转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W ...
- WebService – 2.动态调用WebService
在本节课程中,将演示如何通过程序动态添加.调用.编译.执行WebService并返回结果. WebService动态调用示意图 WebService相关知识 代码文档对象模型CodeDom的使用 编程 ...
- 用C#通过反射实现动态调用WebService 告别Web引用
我们都知道,调用WebService可以在工程中对WebService地址进行WEB引用,但是这确实很不方便.我想能够利用配置文件灵活调用WebService.如何实现呢? 用C#通过反射实现动态调用 ...
- 动态调用Webservice 支持Soapheader身份验证(转)
封装的WebserviceHelp类: using System; using System.CodeDom; using System.CodeDom.Compiler; using System. ...
随机推荐
- ZOJ 3696 Alien's Organ
泊松分布.... Alien's Organ Time Limit: 2 Seconds Memory Limit: 65536 KB There's an alien whose name ...
- CSS背景background详解,background-position详解
背景(background)是css中一个重要的的部分,也是需要知道的css的基础知识之一.这篇文章将会涉及css背景(background)的基本用法,包括诸如 background-attachm ...
- ReactiveCocoa源码拆分解析(三)
(整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 这一章节主要讨论信号的“冷”与“热” 在RAC的世界 ...
- oracle中 SELECT INTO 和INSERT INTO ... SELECT区别
在Oracle中,将一张表的数据复制到另外一个对象中.通常会有这两种方法:insert into select 和 select into from. 前者可以将select 出来的N行(0到任意数 ...
- BZOJ2007——[Noi2010]海拔
1.题意:一个裸的最小割 2.分析:直接转成对偶图最短路就好了,水爆了!(雾) #include <queue> #include <cstdio> #include < ...
- 整理iOS9适配中出现的坑(图文)
原文: http://www.cnblogs.com/dsxniubility/p/4821184.html 整理iOS9适配中出现的坑(图文) 本文主要是说一些iOS9适配中出现的坑,如果只是要 ...
- Count Complete Tree Nodes
Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...
- iOS开发UI篇—CAlayer层的属性
iOS开发UI篇—CAlayer层的属性 一.position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性:position和anchorPoint @property ...
- 使用 PowerDesigner 和 PDMReader 逆向生成 MySQL 数据字典
下面提到的软件大家可以在下面的链接下载. 大家可以参考下面的操作录制视频来完成相关的操作. 使用 PowerDesigner 和 PDMReader 逆向生成 MySQL 数据字典.wmv_免费高速下 ...
- 低功耗蓝牙BLE之连接事件、连接参数和更新方法
转自:http://blog.csdn.net/zzfenglin/article/details/51304084 连接事件 在一个连接当中,主设备会在每个连接事件里向从设备发送数据包.一个连接事件 ...