C# 动态调用WebService

Reference from : http://blog.csdn.net/chuxiamuxiang/article/details/5731988

在C#程序中,若要调用WebService,一般是采用"添加Web引用"的方式来实现的。但如果此WebService的URL是在程序运行过程中才能获得的,那怎么办呢?那就必须是"动态"调用这个WebService了。

网上有不少关于这方面的例子,总结了一下,主要有两种:(1)每次都动态调用,(2)将WebService生成为一个本地的DLL,生成客户端的实例。

第一种方法:

我把它放到一个叫WebServiceHelper.cs的类里面了。

[c-sharp] view plaincopy

  1. /// <summary>
  2. /// 动态调用WebService
  3. /// </summary>
  4. /// <param name="url">WebService地址</param>
  5. /// <param name="classname">类名</param>
  6. /// <param name="methodname">方法名(模块名)</param>
  7. /// <param name="args">参数列表</param>
  8. /// <returns>object</returns>
  9. public static object InvokeWebService(string url, string classname, string methodname, object[] args)
  10. {
  11. string @namespace = "ServiceBase.WebService.DynamicWebLoad";
  12. if (classname == null || classname == "")
  13. {
  14. classname = WebServiceHelper.GetClassName(url);
  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 StringBuilder();
  42. foreach (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. private static string GetClassName(string url)
  57. {
  58. string[] parts = url.Split(‘/‘);
  59. string[] pps = parts[parts.Length - 1].Split(‘.‘);
  60. return pps[0];
  61. }

举个使用它的例子:

[c-sharp] view plaincopy

  1. object[] args = new object[1];
  2. args.SetValue("cyy_JS", 0);
  3. DataTable dt = WebServiceHelper.InvokeWebService("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx", "GetUserTreeListData", args) as DataTable;

恩~有点麻烦,这意味着每次我都要把想调用的函数的参数组织成一个object[]才行,且每次调用InvokeWebService都是在内存中创建动态程序集,效率极低。则次种方法绝对没有直接用“实例名.方法名(参数列表)”来的舒服。

第二种方法:

为了提高效率,希望不要每次都创建这么一个动态程序集,那么就要把这个程序集保存在本地,使用的时候调用这个本地的DLL即可。

首先要调用:WebServiceHelper.CreateWebServiceDLL(); 用来在Debug目录下生成dll。这个函数的代码如下:

[c-sharp] view plaincopy

  1. public static void CreateWebServiceDLL()
  2. {
  3. // 1. 使用 WebClient 下载 WSDL 信息。
  4. WebClient web = new WebClient();
  5. Stream stream = web.OpenRead("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx?WSDL");
  6. // 2. 创建和格式化 WSDL 文档。
  7. ServiceDescription description = ServiceDescription.Read(stream);
  8. // 3. 创建客户端代理代理类。
  9. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  10. importer.ProtocolName = "Soap"; // 指定访问协议。
  11. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  12. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
  13. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  14. // 4. 使用 CodeDom 编译客户端代理类。
  15. CodeNamespace nmspace = new CodeNamespace();        // 为代理类添加命名空间,缺省为全局空间。
  16. CodeCompileUnit unit = new CodeCompileUnit();
  17. unit.Namespaces.Add(nmspace);
  18. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
  19. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  20. CompilerParameters parameter = new CompilerParameters();
  21. parameter.GenerateExecutable = false;
  22. parameter.OutputAssembly = "DBMS_Service.dll";  // 可以指定你所需的任何文件名。
  23. parameter.ReferencedAssemblies.Add("System.dll");
  24. parameter.ReferencedAssemblies.Add("System.XML.dll");
  25. parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
  26. parameter.ReferencedAssemblies.Add("System.Data.dll");
  27. CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
  28. if (result.Errors.HasErrors)
  29. {
  30. // 显示编译错误信息
  31. System.Text.StringBuilder sb = new StringBuilder();
  32. foreach (CompilerError ce in result.Errors)
  33. {
  34. sb.Append(ce.ToString());
  35. sb.Append(System.Environment.NewLine);
  36. }
  37. throw new Exception(sb.ToString());
  38. }
  39. }

下面举个使用的例子:

[c-sharp] view plaincopy

  1. Assembly asm = Assembly.LoadFrom("DBMS_Service.dll");
  2. Type t = asm.GetType("DBMS_Service");
  3. object o = Activator.CreateInstance(t);
  4. MethodInfo method = t.GetMethod("GetUserTreeListData");
  5. object[] args = new object[1];
  6. args.SetValue("cyy_JS", 0);
  7. DataTable dt = method.Invoke(o, args) as DataTable;

这种方法的好处就是只用创建一次程序集,但缺点仍是调用函数的方式比较麻烦。

第二种方法升级版:

哈哈,这个是我自创的。目的就是为了解决:只创建一次DLL;以类似“实例名.方法名(参数列表)”的方式来调用函数;以这个DLL为模板,若WebService的内容有更新时,可同时更新这个本地的DLL。

代码如下:

[c-sharp] view plaincopy

  1. /// <summary>
  2. /// 根据WebService的URL,生成一个本地的dll,放在C盘下面,例如:C:|DBMS_WebService.dll
  3. /// 创建人:程媛媛 创建时间:2010-6-21
  4. /// </summary>
  5. /// <param name="url">WebService的UR</param>
  6. /// <returns></returns>
  7. public static void CreateWebServiceDLL(string url)
  8. {
  9. string @namespace = "ServiceBase.WebService.DynamicWebLoad";
  10. string classname = WebServiceHelper.GetClassName(url);
  11. // 1. 使用 WebClient 下载 WSDL 信息。
  12. WebClient web = new WebClient();
  13. Stream stream = web.OpenRead(url + "?WSDL");
  14. // 2. 创建和格式化 WSDL 文档。
  15. ServiceDescription description = ServiceDescription.Read(stream);
  16. // 3. 创建客户端代理代理类。
  17. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  18. importer.ProtocolName = "Soap"; // 指定访问协议。
  19. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  20. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
  21. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  22. // 4. 使用 CodeDom 编译客户端代理类。
  23. CodeNamespace nmspace = new CodeNamespace(@namespace); // 为代理类添加命名空间,缺省为全局空间。
  24. CodeCompileUnit unit = new CodeCompileUnit();
  25. unit.Namespaces.Add(nmspace);
  26. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
  27. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  28. CompilerParameters parameter = new CompilerParameters();
  29. parameter.GenerateExecutable = false;
  30. parameter.OutputAssembly = "C://DBMS_Service.dll";  // 可以指定你所需的任何文件名。
  31. parameter.ReferencedAssemblies.Add("System.dll");
  32. parameter.ReferencedAssemblies.Add("System.XML.dll");
  33. parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
  34. parameter.ReferencedAssemblies.Add("System.Data.dll");
  35. CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
  36. if (result.Errors.HasErrors)
  37. {
  38. // 显示编译错误信息
  39. System.Text.StringBuilder sb = new StringBuilder();
  40. foreach (CompilerError ce in result.Errors)
  41. {
  42. sb.Append(ce.ToString());
  43. sb.Append(System.Environment.NewLine);
  44. }
  45. throw new Exception(sb.ToString());
  46. }
  47. }

首先调用CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")来生成“C:/DBMS_WebService.dll”;

接着,把这个DLL添加到工程的“引用”当中。

也许你会问,为什么不直接把DBMS_WebService.dll放在debug下?答案是,当把DBMS_WebService.dll添加为 引用时,若在程序运行过程中要更新(包括删了重新创建)它,则会报错。尝试了几次,被我发现,是不能放在Debug下的,其他的任何路径都可以,例如 bin目录下都可以,具体原因我不知道...

既然都把DBMS_WebService.dll添加为引用了,那么便可以先声明它了:

[c-sharp] view plaincopy

  1. public static ServiceBase.WebService.DynamicWebLoad.DBMS_Service pDBMS_Service;

注意:“public static ServiceBase.WebService.DynamicWebLoad.DBMS_Service”是我们调用 CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")的过程 中自定的表空间名。

接下来的事就是,需要一个函数,用来以此DBMS_WebService.dll为模板,用传入的URL来重新生成并覆盖这个DLL,并且,为了省 事,直接返回一个ServiceBase.WebService.DynamicWebLoad.DBMS_Service的实例。

代码如下:

[c-sharp] view plaincopy

  1. /// <summary>
  2. /// 根据WebService的URL,生成一个本地的dll,并返回WebService的实例
  3. /// 创建人:程媛媛 创建时间:2010-6-21
  4. /// </summary>
  5. /// <param name="url">WebService的UR</param>
  6. /// <returns></returns>
  7. public static object GetWebServiceInstance(string url)
  8. {
  9. string @namespace = "ServiceBase.WebService.DynamicWebLoad";
  10. string classname = WebServiceHelper.GetClassName(url);
  11. // 1. 使用 WebClient 下载 WSDL 信息。
  12. WebClient web = new WebClient();
  13. Stream stream = web.OpenRead(url + "?WSDL");
  14. // 2. 创建和格式化 WSDL 文档。
  15. ServiceDescription description = ServiceDescription.Read(stream);
  16. // 3. 创建客户端代理代理类。
  17. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  18. importer.ProtocolName = "Soap"; // 指定访问协议。
  19. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  20. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
  21. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  22. // 4. 使用 CodeDom 编译客户端代理类。
  23. CodeNamespace nmspace = new CodeNamespace(@namespace); // 为代理类添加命名空间,缺省为全局空间。
  24. CodeCompileUnit unit = new CodeCompileUnit();
  25. unit.Namespaces.Add(nmspace);
  26. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
  27. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  28. CompilerParameters parameter = new CompilerParameters();
  29. parameter.GenerateExecutable = false;
  30. parameter.OutputAssembly = "C://DBMS_Service.dll"; // 可以指定你所需的任何文件名。
  31. parameter.ReferencedAssemblies.Add("System.dll");
  32. parameter.ReferencedAssemblies.Add("System.XML.dll");
  33. parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
  34. parameter.ReferencedAssemblies.Add("System.Data.dll");
  35. CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
  36. if (result.Errors.HasErrors)
  37. {
  38. // 显示编译错误信息
  39. System.Text.StringBuilder sb = new StringBuilder();
  40. foreach (CompilerError ce in result.Errors)
  41. {
  42. sb.Append(ce.ToString());
  43. sb.Append(System.Environment.NewLine);
  44. }
  45. throw new Exception(sb.ToString());
  46. }
  47. //生成代理实例
  48. System.Reflection.Assembly assembly = Assembly.Load("DBMS_Service");
  49. Type t = assembly.GetType(@namespace + "." + classname, true, true);
  50. object obj = Activator.CreateInstance(t);
  51. return obj;
  52. }

一切准备就绪,在主程序中这样使用它:

[c-sharp] view plaincopy

  1. object o = WebServiceHelper.GetWebServiceInstance(this.WebServiceURL);
  2. pDBMS_Service = o as ServiceBase.WebService.DynamicWebLoad.DBMS_Service;
  3. DataTable dt = pDBMS_Service.GetUserTreeListData(this.UserName);
时间: 2024-12-05 22:40:58

C# 动态调用WebService的相关文章

动态调用webservice

public static class WebserviceHelper { /// <summary> /// 动态调用WebService /// </summary> /// <param name="url">WebService地址</param> /// <param name="methodname">方法名(模块名)</param> /// <param name=&quo

[转]Net 下采用GET/POST/SOAP方式动态调用WebService C#实现

本文转自:http://www.cnblogs.com/splendidme/archive/2011/10/05/2199501.html 一直以来,我们都为动态调用WebService方法而烦恼.在.Net环境下,最常用的方法就是采用代理类来调用WebService,可以通过改变代理类的Url属性来实现动态调用,但当xmlns改变时就会出错,似乎要重新绑定Webservice并重新编译后才能再次运行.我无意中通过百度搜索找了一个采用GET/POST/SOAP方式动态调用WebService的

动态调用WebService(C#) (非常实用)

前言 站在开发者的角度,WebService 技术确实是不再“时髦”.甚至很多人会说,我们不再用它.当然,为了使软件可以更简洁,更有层次,更易于实现缓存等机制,我是非常建议将 SOAP 转为 RESTful 架构风格的.但到目前为止,WebService 在一些Public Institution 中使用还是十分广泛的. 这里主要讨论一下关于WebService的调用问题.关于WebService 的调用分为静态调用和动态调用两种,外加直接Http请求方式 静态调用 静态调用的方式是通过“Add

C# 动态调用 WebService (转)

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

动态调用WebService时动态获取返回Class中的属性

直接给代码: var ret = HTTPS.WSHelper.InvokeWebService("WebService URL", "MethodName", object[] args);var type = ret.GetType();var propertyinfo = type.GetProperty("result");if (propertyinfo == null){       throw new Exception("

不添加引用,动态调用WebService

这两天给公司写一个调用接口的程序,接口采用WebService! 本打算将这个工具写成通用的,但是微软给出的调用WebService的方法必须添加该WebService引用,这样的方式不免太过于死板,无法动态调用,于是在网上查了很多相关解决办法!自己封装成了一个函数,发布出来,做个纪念! using System.Net; using System.IO; using System.Web.Services.Description; using System.CodeDom; using Sys

C#中Winform动态调用Webservice的方法(转)

一般情况下winform调用webservice时步骤 1添加服务引用---高级----添加web引用------填写url--添加web引用即可完成对webservice的引用 让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务. 如果需要动态调用WebService,要实现这样的功能: publicstaticobjectInvokeWebService(stringurl,  stringmethodname,object[] args) 其中,url是Web服务的地址,me

Web Service学习笔记:动态调用WebService

原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务.在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西. 具体步骤: 1. 从目标 URL 下载 WSDL 数据. 2. 使用 ServiceDescription 创建和格式化 WSDL

C# .NET 动态调用webservice的三种方式

转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W4iPZcjAW6q8vu45QOjK6DSUon1R10ePVlqG6nwussbbXE6jm 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务.在 .NET Framework