动态调用WebService(C#)

时间:2022-09-24 15:06:42

通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却和提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果哪一天发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。在某些情况下,这可能是不能忍受的,我们需要动态调用WebService的能力。比如我们可以把Web服务的URL保存在配置文件中,这样,当服务URL改变时,只需要修改配置文件就可以了。
     说了这么多,实际上我们要实现这样的功能:

  1. 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服务的动态调用了:

  1. #region InvokeWebService
  2. //动态调用web服务
  3. public static object InvokeWebService(string url, string methodname, object[] args)
  4. {
  5. return WebServiceHelper.InvokeWebService(url ,null ,methodname ,args) ;
  6. }
  7. public static object InvokeWebService(string url,  string classname, string methodname, object[] args)
  8. {
  9. string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;
  10. if((classname == null) ||(classname == ""))
  11. {
  12. classname = WebServiceHelper.GetWsClassName(url) ;
  13. }
  14. try
  15. {
  16. //获取WSDL
  17. WebClient wc                   = new WebClient();
  18. Stream stream                  = wc.OpenRead(url+"?WSDL");
  19. ServiceDescription sd          = ServiceDescription.Read(stream);
  20. ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
  21. sdi.AddServiceDescription(sd,"","");
  22. CodeNamespace cn                = new CodeNamespace(@namespace);
  23. //生成客户端代理类代码
  24. CodeCompileUnit ccu             = new CodeCompileUnit();
  25. ccu.Namespaces.Add(cn);
  26. sdi.Import(cn ,ccu);
  27. CSharpCodeProvider csc          = new CSharpCodeProvider();
  28. ICodeCompiler icc               = csc.CreateCompiler();
  29. //设定编译参数
  30. CompilerParameters cplist       = new CompilerParameters();
  31. cplist.GenerateExecutable       = false;
  32. cplist.GenerateInMemory         = true;
  33. cplist.ReferencedAssemblies.Add("System.dll");
  34. cplist.ReferencedAssemblies.Add("System.XML.dll");
  35. cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
  36. cplist.ReferencedAssemblies.Add("System.Data.dll");
  37. //编译代理类
  38. CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
  39. if(true == cr.Errors.HasErrors)
  40. {
  41. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  42. foreach(System.CodeDom.Compiler.CompilerError ce in cr.Errors)
  43. {
  44. sb.Append(ce.ToString());
  45. sb.Append(System.Environment.NewLine);
  46. }
  47. throw new Exception(sb.ToString());
  48. }
  49. //生成代理实例,并调用方法
  50. System.Reflection.Assembly assembly = cr.CompiledAssembly;
  51. Type t = assembly.GetType(@namespace+"."+classname,true,true);
  52. object obj = Activator.CreateInstance(t);
  53. System.Reflection.MethodInfo mi = t.GetMethod(methodname);
  54. return mi.Invoke(obj,args);
  55. }
  56. catch(Exception ex)
  57. {
  58. throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
  59. }
  60. }
  61. private static string GetWsClassName(string wsUrl)
  62. {
  63. string[] parts = wsUrl.Split('/') ;
  64. string[] pps   = parts[parts.Length-1].Split('.') ;
  65. return pps[0] ;
  66. }
  67. #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 服务来获取各大城市的天气状况。

  1. string url = "http://www.webservicex.net/globalweather.asmx" ;
  2. string[] args = new string[2] ;
  3. args[0] = this.textBox_CityName.Text ;
  4. args[1] = "China" ;
  5. object result = WebServiceHelper.InvokeWebService(url ,"GetWeather" ,args) ;
  6. 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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Xml;
  5. using System.Net;
  6. using System.Web.Services.Description;
  7. using System.CodeDom;
  8. using System.CodeDom.Compiler;
  9. using System.Reflection;
  10. namespace WindowsServiceWebDefaultHotCity
  11. {
  12. /// <summary<
  13. /// WebService代理类
  14. /// </summary<
  15. public class WebServiceAgent
  16. {
  17. private object agent;
  18. private Type agentType;
  19. private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
  20. /// <summary<
  21. /// 构造函数
  22. /// </summary<
  23. /// <param name="url"<</param<
  24. public WebServiceAgent(string url)
  25. {
  26. XmlTextReader reader = new XmlTextReader(url + "?wsdl");
  27. //创建和格式化 WSDL 文档
  28. ServiceDescription sd = ServiceDescription.Read(reader);
  29. //创建客户端代理代理类
  30. ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
  31. sdi.AddServiceDescription(sd, null, null);
  32. //使用 CodeDom 编译客户端代理类
  33. CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
  34. CodeCompileUnit ccu = new CodeCompileUnit();
  35. ccu.Namespaces.Add(cn);
  36. sdi.Import(cn, ccu);
  37. Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();
  38. CompilerParameters cp = new CompilerParameters();
  39. CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
  40. agentType = cr.CompiledAssembly.GetTypes()[0];
  41. agent = Activator.CreateInstance(agentType);
  42. }
  43. ///<summary<
  44. ///调用指定的方法
  45. ///</summary<
  46. ///<param name="methodName"<方法名,大小写敏感</param<
  47. ///<param name="args"<参数,按照参数顺序赋值</param<
  48. ///<returns<Web服务的返回值</returns<
  49. public object Invoke(string methodName, params object[] args)
  50. {
  51. MethodInfo mi = agentType.GetMethod(methodName);
  52. return this.Invoke(mi, args);
  53. }
  54. ///<summary<
  55. ///调用指定方法
  56. ///</summary<
  57. ///<param name="method"<方法信息</param<
  58. ///<param name="args"<参数,按照参数顺序赋值</param<
  59. ///<returns<Web服务的返回值</returns<
  60. public object Invoke(MethodInfo method, params object[] args)
  61. {
  62. return method.Invoke(agent, args);
  63. }
  64. public MethodInfo[] Methods
  65. {
  66. get
  67. {
  68. return agentType.GetMethods();
  69. }
  70. }
  71. }
  72. }
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();
}
}
}
}
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. namespace WindowsApplication1
  9. {
  10. public partial class Form1 : Form
  11. {
  12. private string _url = "http://www.baidu.com";
  13. public Form1()
  14. {
  15. InitializeComponent();
  16. init_Data();
  17. }
  18. public void init_Data()
  19. {
  20. WindowsServiceWebDefaultHotCity.WebServiceAgent agent = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
  21. object[] args = new object[6];
  22. args[0] = "PEK";
  23. args[1] = "CAN";
  24. args[2] = "";
  25. args[3] = "2008-08-02";
  26. args[4] = "00:00";
  27. args[5] = "own_9588";
  28. string text=agent.Invoke("GetAllFlight", args).ToString();
  29. textBox1.Text = text;
  30. }
  31. }
  32. }
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;
}
}
}
  1. 我们都知道,调用WS可以在工程中添加对WS的WEB引用。
  2. 但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢?
  3. 首先,我们该想到WS的实现也是一个类的形式。
  4. 其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。
  5. 因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。
  6. 最后:通过反射来获取新生成的程序集,并调用其方法!
  7. 上述步骤需要引用如下四个名称空间:
  8. using System.Web.Services.Description; //WS的描述
  9. //以下几个用于根据描述动态生成代码并动态编译获取程序集
  10. using System.CodeDom;
  11. using Microsoft.CSharp;
  12. using System.CodeDom.Compiler;
  13. 上述几个名称空间中包括如下几个重要的类:
  14. using System.Web.Services.Description下:
  15. ServiceDescription //WS描述
  16. ServiceDescriptionImporter //通过描述生成客户端代理类,特别注意其中的Style
  17. 以下是MSDN对其的描述:
  18. 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 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
  19. using System.CodeDom下:
  20. 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。

方法如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net;
  5. using System.IO;
  6. using System.Web.Services.Description;
  7. using System.CodeDom;
  8. using Microsoft.CSharp;
  9. using System.CodeDom.Compiler;
  10. namespace TestSkin
  11. {
  12. class Webservices
  13. {
  14. /// <summary<
  15. /// 实例化WebServices
  16. /// </summary<
  17. /// <param name="url"<WebServices地址</param<
  18. /// <param name="methodname"<调用的方法</param<
  19. /// <param name="args"<把webservices里需要的参数按顺序放到这个object[]里</param<
  20. public static object InvokeWebService(string url, string methodname, object[] args)
  21. {
  22. //这里的namespace是需引用的webservices的命名空间,在这里是写死的,大家可以加一个参数从外面传进来。
  23. string @namespace = "client";
  24. try
  25. {
  26. //获取WSDL
  27. WebClient wc = new WebClient();
  28. Stream stream = wc.OpenRead(url + "?WSDL");
  29. ServiceDescription sd = ServiceDescription.Read(stream);
  30. string classname = sd.Services[0].Name;
  31. ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
  32. sdi.AddServiceDescription(sd, "", "");
  33. CodeNamespace cn = new CodeNamespace(@namespace);
  34. //生成客户端代理类代码
  35. CodeCompileUnit ccu = new CodeCompileUnit();
  36. ccu.Namespaces.Add(cn);
  37. sdi.Import(cn, ccu);
  38. CSharpCodeProvider csc = new CSharpCodeProvider();
  39. ICodeCompiler icc = csc.CreateCompiler();
  40. //设定编译参数
  41. CompilerParameters cplist = new CompilerParameters();
  42. cplist.GenerateExecutable = false;
  43. cplist.GenerateInMemory = true;
  44. cplist.ReferencedAssemblies.Add("System.dll");
  45. cplist.ReferencedAssemblies.Add("System.XML.dll");
  46. cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
  47. cplist.ReferencedAssemblies.Add("System.Data.dll");
  48. //编译代理类
  49. CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
  50. if (true == cr.Errors.HasErrors)
  51. {
  52. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  53. foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
  54. {
  55. sb.Append(ce.ToString());
  56. sb.Append(System.Environment.NewLine);
  57. }
  58. throw new Exception(sb.ToString());
  59. }
  60. //生成代理实例,并调用方法
  61. System.Reflection.Assembly assembly = cr.CompiledAssembly;
  62. Type t = assembly.GetType(@namespace + "." + classname, true, true);
  63. object obj = Activator.CreateInstance(t);
  64. System.Reflection.MethodInfo mi = t.GetMethod(methodname);
  65. return mi.Invoke(obj, args);
  66. }
  67. catch
  68. {
  69. return null;
  70. }
  71. }
  72. }
  73. }
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的类名最好是一样的。不过就算不符合这条件也没关系,后面我会在注释中注明的。看代码:

  1. using System;
  2. using System.CodeDom;
  3. using System.CodeDom.Compiler;
  4. using System.IO;
  5. using System.Net;
  6. using System.Reflection;
  7. using System.Web.Services.Description;
  8. using Microsoft.CSharp;
  9. //获取Web Service描述
  10. WebClient wc= new WebClient();
  11. Stream stream = wc.OpenRead("http://localhost/TestService.asmx?WSDL");  //这里指定你自己的web service url,一定要以?WSDL结尾
  12. ServiceDescription sd = ServiceDescription.Read(stream);
  13. ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
  14. sdi.ProtocolName = "soap";
  15. sdi.Style = ServiceDescriptionImportStyle.Client;
  16. sdi.AddServiceDescription(sd, null, null);
  17. //指定命名空间
  18. CodeNamespace cn = new CodeNamespace("Test");  //这里随便指定一个命名空间,但要与后面的一致
  19. CodeCompileUnit ccu = new CodeCompileUnit();
  20. ccu.Namespaces.Add(cn);
  21. sdi.Import(cn, ccu);
  22. 建立C#编译器
  23. CSharpCodeProvider csc = new CSharpCodeProvider();
  24. ICodeCompiler icc = csc.CreateCompiler();
  25. CompilerParameters cp = new CompilerParameters();
  26. cp.GenerateExecutable = false;
  27. cp.GenerateInMemory = true;
  28. //添加编译条件
  29. cp.ReferencedAssemblies.Add("System.dll");
  30. cp.ReferencedAssemblies.Add("System.XML.dll");
  31. cp.ReferencedAssemblies.Add("System.Web.Services.dll");
  32. //编译程序集
  33. CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
  34. //检查是否编译成功
  35. if (!cr.Errors.HasErrors)
  36. {
  37. //编译成功
  38. //获取程序集
  39. Assembly assembly = cr.CompiledAssembly;
  40. //获取程序集类型
  41. //前面的Test就是命名空间,必须要与前面指定的一致
  42. //后面的TestService就是service的类名
  43. //如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名
  44. Type type = assembly.GetType("Test.TestService", true);
  45. object service = Activator.CreateInstance(type);
  46. //获取方法
  47. //如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名
  48. MethodInfo mi = type.GetMethod("HelloWorld");
  49. //调用方法
  50. //如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致
  51. //如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序
  52. mi.Invoke(service, null);
  53. //最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。
  54. }
  55. else
  56. {
  57. //这里自己处理编译错误
  58. }
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
{
//这里自己处理编译错误
} 转自:http://www.cnblogs.com/chenmfly/p/4463422.html
http://www.cnblogs.com/xuwb/archive/2012/09/25/2701629.html

动态调用WebService(C#)的更多相关文章

  1. Atitit 动态调用webservice与客户端代理方式调用

    Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke  直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...

  2. 动态调用WebService&lpar;C&num;&rpar; (非常实用)

    通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...

  3. 动态调用webservice&lpar;部分转载&rpar;

    动态调用webservice,做个笔记: public class WSHelper { /// < summary> /// 动态调用web服务 /// < /summary&gt ...

  4. C&num; 动态调用webservice

    最近项目中,用到动态调用webservice的内容,此处记录下来,留着以后COPY(我们只需要在XML,config文件,或者数据库中配置webservice连接地址和方法名即可使用): using ...

  5. 动态调用webservice及WCF服务

    动态调用web服务,该方法只针对Web service, WCF的服务不行,如果是WCF的就通过工具直接生产代理类,把代理类配置到调用的项目中,通过配置客户端的终结点动态的取实现: 通过Svcutil ...

  6. C&num; &period;NET 动态调用webservice的三种方式

    转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W ...

  7. WebService – 2&period;动态调用WebService

    在本节课程中,将演示如何通过程序动态添加.调用.编译.执行WebService并返回结果. WebService动态调用示意图 WebService相关知识 代码文档对象模型CodeDom的使用 编程 ...

  8. 用C&num;通过反射实现动态调用WebService 告别Web引用

    我们都知道,调用WebService可以在工程中对WebService地址进行WEB引用,但是这确实很不方便.我想能够利用配置文件灵活调用WebService.如何实现呢? 用C#通过反射实现动态调用 ...

  9. 动态调用Webservice 支持Soapheader身份验证&lpar;转&rpar;

    封装的WebserviceHelp类: using System; using System.CodeDom; using System.CodeDom.Compiler; using System. ...

  10. &lbrack;转&rsqb;Net 下采用GET&sol;POST&sol;SOAP方式动态调用WebService C&num;实现

    本文转自:http://www.cnblogs.com/splendidme/archive/2011/10/05/2199501.html 一直以来,我们都为动态调用WebService方法而烦恼. ...

随机推荐

  1. iOS—Mask属性的使用

    Mask属性介绍 Mask平时用的最多的是masksToBounds 吧. 其实除此以外Mask使用场景很多,看完之后你会发现好真是好用的不要不要的... 先来了解下Mask属性到底是什么? Mask ...

  2. C&num; 格式化字符串,日期,字符串操作汇总

    时间格式化 有时候我们要对时间进行转换,达到不同的显示效果 默认格式为:2005-6-6 14:33:34 如果要换成成200506,06-2005,2005-6-6或更多的该怎么办呢 我们要用到:D ...

  3. Windows x86 x64使用SetThreadContext注入shellcode的方式加载DLL

    一.前言 注入DLL的方式有很多,在R3就有远程线程CreateRemoteThread.SetWindowsHookEx.QueueUserApc.SetThreadContext 在R0可以使用a ...

  4. 如何使用命令行cmd执行java程序

    如果你的电脑上没有像idea eclipse这类的IDE,但是因为工作需要必须要执行java代码怎么办呢? 这个时候就需要使用电脑最原始的执行方式 既命令行 1:首先你得安装了jdk与jre (这里就 ...

  5. PAT 甲级 1083 List Grades (25 分)

    1083 List Grades (25 分) Given a list of N student records with name, ID and grade. You are supposed ...

  6. &lbrack;Python&rsqb; 制作启动uiautomator2 的web版 uiautomatorviewer2 批处理启动

    打开一个txt文件,复制如下命令进行并另存为为 .bat文件 @echo on @echo 正在启动 uiautomatorviewer2 python -m weditor @echo off 注意 ...

  7. android周期性任务

    一般任务调度机制的实现方式主要有: Thread sleep.Timer.ScheduledExecutor.Handler和其他第三方开源库.android的AlarmManager 1. Time ...

  8. webBrowser1&period;Document&period;Cookie取不到HttpOnly的Cookie,取Cookie不完整【转】

    在做数据采集时,有些网站需要输入验证码,但各网站验证码都不同,不可能有完美的识别验证码的代码,所以我也没去研究,我所采取的方案是:在winform里通过WebBrowser调用网页先手动登录系统,然后 ...

  9. Eclipse&colon; User Operation is waiting for &OpenCurlyDoubleQuote;Building Workspace”

    这个情况可能有多个原因导致,比如,非正常关闭eclipse,时钟不匹配等等,可能解决的方法有: 1. 删除<workspace_folder>/.metadata/.lock文件 2. e ...

  10. 转载:什么才是真正的 RESTful 架构

    What? Wikipedia: 表征性状态传输(英文:Representational State Transfer,简称REST)是Roy Fielding博士于2000年在他的博士论文中提出来的 ...