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

多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务。在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西。



具体步骤:



1. 从目标 URL 下载 WSDL 数据。

2. 使用 ServiceDescription 创建和格式化 WSDL 文档文件。

3. 使用 ServiceDescriptionImporter 创建客户端代理类。

4. 使用 CodeDom 动态创建客户端代理类程序集。

5. 利用反射调用相关 WebService 方法。



OK,看看具体的例子。



我们要调用的目标 WebService,其 URL 是 http://localhost:60436/Learn.WEB/WebService.asmx

  1. HelloWorld.asmx [WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
  2. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  3. public class WebService : System.Web.Services.WebService {
  4.  
  5. public WebService () {
  6. }
  7.  
  8.   [WebMethod]
  9.   public string HelloWorld()
  10.   {
  11.     return "Hello Wolrd!";
  12.   }
  13. }
  14.  
  15. 1. 动态调用 WebService
  16.  
  17. 客户端动态调用代码
  18. using System.IO;
  19. using System.Net;
  20. using System.Reflection;
  21. using System.CodeDom;
  22. using System.CodeDom.Compiler;
  23. using System.Web.Services;
  24. using System.Web.Services.Description;
  25. using System.Web.Services.Protocols;
  26. using System.Xml.Serialization;
  27.  
  28. // 1. 使用 WebClient 下载 WSDL 信息。
  29. WebClient web = new WebClient();
  30. Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
  31.  
  32. // 2. 创建和格式化 WSDL 文档。
  33. ServiceDescription description = ServiceDescription.Read(stream);
  34.  
  35. // 3. 创建客户端代理代理类。
  36. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  37.  
  38. importer.ProtocolName = "Soap"; // 指定访问协议。
  39. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  40. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 
  41.  
  42. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  43.  
  44. // 4. 使用 CodeDom 编译客户端代理类。
  45. CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
  46. CodeCompileUnit unit = new CodeCompileUnit();
  47. unit.Namespaces.Add(nmspace);
  48.  
  49. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
  50. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  51.  
  52. CompilerParameters parameter = new CompilerParameters();
  53. parameter.GenerateExecutable = false;
  54. parameter.GenerateInMemory = true;
  55. parameter.ReferencedAssemblies.Add("System.dll");
  56. parameter.ReferencedAssemblies.Add("System.XML.dll");
  57. parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
  58. parameter.ReferencedAssemblies.Add("System.Data.dll");
  59.  
  60. CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
  61.  
  62. // 5. 使用 Reflection 调用 WebService。
  63. if (!result.Errors.HasErrors)
  64. {
  65.   Assembly asm = result.CompiledAssembly;
  66.   Type t = asm.GetType("WebService"); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。
  67.  
  68.   object o = Activator.CreateInstance(t);
  69.   MethodInfo method = t.GetMethod("HelloWorld");
  70.   Console.WriteLine(method.Invoke(o, null));
  71. }

2. 生成客户端代理程序集文件



上面的代码通过在内存中创建动态程序集的方式完成了动态调用过程。如果我们希望将客户端代理类生成程序集文件保存到硬盘,则可以进行如下修改。生成程序集文件后,我们可以通过 Assembly.LoadFrom() 载入并进行反射调用。对于需要多次调用的系统,要比每次生成动态程序集效率高出很多。

  1. using System.IO;
  2. using System.Net;
  3. using System.CodeDom;
  4. using System.CodeDom.Compiler;
  5. using System.Web.Services;
  6. using System.Web.Services.Description;
  7. using System.Web.Services.Protocols;
  8. using System.Xml.Serialization;
  9.  
  10. // 1. 使用 WebClient 下载 WSDL 信息。
  11. WebClient web = new WebClient();
  12. Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
  13.  
  14. // 2. 创建和格式化 WSDL 文档。
  15. ServiceDescription description = ServiceDescription.Read(stream);
  16.  
  17. // 3. 创建客户端代理代理类。
  18. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  19.  
  20. importer.ProtocolName = "Soap"; // 指定访问协议。
  21. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  22. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 
  23.  
  24. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  25.  
  26. // 4. 使用 CodeDom 编译客户端代理类。
  27. CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
  28. CodeCompileUnit unit = new CodeCompileUnit();
  29. unit.Namespaces.Add(nmspace);
  30.  
  31. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
  32. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  33.  
  34. CompilerParameters parameter = new CompilerParameters();
  35. parameter.GenerateExecutable = false;
  36. parameter.OutputAssembly = "test.dll"; // 可以指定你所需的任何文件名。
  37. parameter.ReferencedAssemblies.Add("System.dll");
  38. parameter.ReferencedAssemblies.Add("System.XML.dll");
  39. parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
  40. parameter.ReferencedAssemblies.Add("System.Data.dll");
  41.  
  42. CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
  43. if (result.Errors.HasErrors)
  44. {
  45.   // 显示编译错误信息
  46. }
  47.  
  48. 调用程序集文件演示
  49. Assembly asm = Assembly.LoadFrom("test.dll");
  50. Type t = asm.GetType("WebService"); 
  51.  
  52. object o = Activator.CreateInstance(t);
  53. MethodInfo method = t.GetMethod("HelloWorld");
  54. Console.WriteLine(method.Invoke(o, null));

3. 获取客户端代理类源代码



还有一种情形,就是我们需要获得客户端代理类的 C# 源代码。

  1. using System.IO;
  2. using System.Net;
  3. using System.CodeDom;
  4. using System.CodeDom.Compiler;
  5. using System.Web.Services;
  6. using System.Web.Services.Description;
  7. using System.Web.Services.Protocols;
  8. using System.Xml.Serialization;
  9.  
  10. // 1. 使用 WebClient 下载 WSDL 信息。
  11. WebClient web = new WebClient();
  12. Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL");
  13.  
  14. // 2. 创建和格式化 WSDL 文档。
  15. ServiceDescription description = ServiceDescription.Read(stream);
  16.  
  17. // 3. 创建客户端代理代理类。
  18. ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
  19.  
  20. importer.ProtocolName = "Soap"; // 指定访问协议。
  21. importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
  22. importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 
  23.  
  24. importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。
  25.  
  26. // 4. 使用 CodeDom 编译客户端代理类。
  27. CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
  28. CodeCompileUnit unit = new CodeCompileUnit();
  29. unit.Namespaces.Add(nmspace);
  30.  
  31. ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
  32. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
  33.  
  34. // 5. 保存源代码到文件。当然,你也可以直接保存到内存字符串中。
  35. TextWriter writer = File.CreateText("test.cs"); // 指定你所需的源代码文件名。
  36. provider.GenerateCodeFromCompileUnit(unit, writer, null);
  37. writer.Flush();
  38. writer.Close();

如果你调用时触发 "WebException: 请求因 HTTP 状态 415 失败: Unsupported Media Type。" 这样的异常,那么恭喜你和我一样郁闷,赶紧把服务器端的 WSE 关掉吧。在必须使用 WSE 的情况下,需要对客户端进行调整.

Web Service学习笔记:动态调用WebService的更多相关文章

  1. Web Service学习笔记(webservice、soap、wsdl、jws详细分析)

    Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API ...

  2. Web Service学习笔记(webservice、soap、wsdl、jws详细分析) (转)

    Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API ...

  3. Web Service学习笔记

    Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API ...

  4. Java Web Service 学习笔记

    一.服务端 1. 创建Java工程 2. 创建接口HostipalServiceInterface package ws_server; import javax.jws.WebMethod; imp ...

  5. 用C#通过反射实现动态调用WebService 告别Web引用

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

  6. 用C#通过反射实现动态调用WebService 告别Web引用(转载)

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

  7. Java web与web gis学习笔记(二)——百度地图API调用

    系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...

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

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

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

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

随机推荐

  1. 通过ccb(CocosBuilder)文件生成cocos2dx代码

    在C++下使用ccb.绑定调用,成员变量.让人头疼又easy犯错. 自己用pythong写了个小程序,通过ccb文件直接生成C++代码 python我用的不多.又是随性所做.代码质量就非常差.大家多多 ...

  2. Attribute(两)——定义自己的特色+Asp.net MVC中间filter详细解释

    部分博客是预先定义的有关特性的一些基本特征,同时还Attribute这一概念的一个宏观上的认识,在上篇博客结尾介绍了有关为自己定义特性服务的AttributeUsage,这篇博客主要是通过filter ...

  3. GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?

    在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢? 由于使用这个类时,并没有增加#include <gdiplus.h> .也没有在程序開始和结束时分别写GDI ...

  4. How to pause the game in Uniy3D

    static float timeScale; Description The scale at which the time is passing. This can be used for slo ...

  5. SDUT 1265-马停下过河卒(DFS)

    马拦过河卒 nid=24#time" title="C.C++.go.haskell.lua.pascal Time Limit3000ms Memory Limit 65536K ...

  6. Hadoop 它们的定义Writable NullpointerException

    Hadoop周边环境:Hadoop2.4 定义中的Hadoop的Writable时间,有时你需要使用数组,而不是简单的单一值或串.例如,下面的代码: package test; import java ...

  7. CSS截取字符串,额外的文本显示以省略号

    最近的诀窍css还有这么叼炸天的侧~~~ 善待似论坛页面,头像70px,但username不限啊,English中国能够.你说如果他采取"我的名字是这么长啊.你该怎么办呢".那老和 ...

  8. C语言文件操作函数大全

    http://blog.csdn.net/mu0206mu/article/details/18980913 clearerr(清除文件流的错误旗标) 相关函数 feof表头文件 #include&l ...

  9. linux0.11学习笔记(2)

    makefile文件: makefile 文件是make 实用简介.make 程序是用Makefile最后一次改变的数据文件和代码文件(last-modification time)确定哪些文件需要更 ...

  10. easyUI的combobox实现级联

    先简介下combobox: easyUI重写了select,取而代之的是combobox,有例如以下几种方式能够创建一个combobox 1.使用select标签,并加上class="eas ...