原文: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

HelloWorld.asmx [WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService { public WebService () {
}   [WebMethod]
  public string HelloWorld()
  {
    return "Hello Wolrd!";
  }
} 1. 动态调用 WebService 客户端动态调用代码
using System.IO;
using System.Net;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml.Serialization; // 1. 使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL"); // 2. 创建和格式化 WSDL 文档。
ServiceDescription description = ServiceDescription.Read(stream); // 3. 创建客户端代理代理类。
ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap"; // 指定访问协议。
importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。 // 4. 使用 CodeDom 编译客户端代理类。
CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace); ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters parameter = new CompilerParameters();
parameter.GenerateExecutable = false;
parameter.GenerateInMemory = true;
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll"); CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); // 5. 使用 Reflection 调用 WebService。
if (!result.Errors.HasErrors)
{
  Assembly asm = result.CompiledAssembly;
  Type t = asm.GetType("WebService"); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。   object o = Activator.CreateInstance(t);
  MethodInfo method = t.GetMethod("HelloWorld");
  Console.WriteLine(method.Invoke(o, null));
}

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



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

using System.IO;
using System.Net;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml.Serialization; // 1. 使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL"); // 2. 创建和格式化 WSDL 文档。
ServiceDescription description = ServiceDescription.Read(stream); // 3. 创建客户端代理代理类。
ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap"; // 指定访问协议。
importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。 // 4. 使用 CodeDom 编译客户端代理类。
CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace); ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters parameter = new CompilerParameters();
parameter.GenerateExecutable = false;
parameter.OutputAssembly = "test.dll"; // 可以指定你所需的任何文件名。
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll"); CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
if (result.Errors.HasErrors)
{
  // 显示编译错误信息
} 调用程序集文件演示
Assembly asm = Assembly.LoadFrom("test.dll");
Type t = asm.GetType("WebService");  object o = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod("HelloWorld");
Console.WriteLine(method.Invoke(o, null));

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



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

using System.IO;
using System.Net;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml.Serialization; // 1. 使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
Stream stream = web.OpenRead("http://localhost:60436/Learn.WEB/WebService.asmx?WSDL"); // 2. 创建和格式化 WSDL 文档。
ServiceDescription description = ServiceDescription.Read(stream); // 3. 创建客户端代理代理类。
ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap"; // 指定访问协议。
importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。 // 4. 使用 CodeDom 编译客户端代理类。
CodeNamespace nmspace = new CodeNamespace(); // 为代理类添加命名空间,缺省为全局空间。
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace); ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); // 5. 保存源代码到文件。当然,你也可以直接保存到内存字符串中。
TextWriter writer = File.CreateText("test.cs"); // 指定你所需的源代码文件名。
provider.GenerateCodeFromCompileUnit(unit, writer, null);
writer.Flush();
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. MS Open Tech 技术团队构建可靠的Windows版Redis

    可靠的Windows版Redis 副标题: 评论更精彩,教你怎么解决64位Windows版Redis狂占C盘的问题. MS Open Tech 技术团队最近花了很多时间来测试最新构建的Windows版 ...

  2. OpenGL中shader使用

    学了接近一个月的OpenGL,最终要排上用场了...好吧,就从学到的shader(着色器)开刀吧. 先简单的介绍shader,shader事实上是显卡的功能,就是利用显卡的GPU去做图像处理的工作,而 ...

  3. Android 按下电源按钮关闭小学习过程的整个长度

    Android 按下电源按钮关闭小学习过程的整个长度 近期研究了一下android关机跟又一次启动功能,看了一些长按电源键到弹出关机对话框,到真正关机的一系列处理过程. 首先还是来看看这个长按电源键都 ...

  4. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  5. 【JAVA】【NIO】5、Java NIO Scatter / Gather

    标题手段Java NIO该分散体浓缩 Java NIO内置支持分散与收集.的概念主要用于信道分散聚集的读写. 读出的分散体的一个通道被读多个数据buffer在.因此.数据分散到多个buffer中. 对 ...

  6. NSIS API 函数常用备份

    原文:NSIS API 函数常用备份 关闭程序: System::Call `user32::AnimateWindow(i$HWNDPARENT,i200,i${AW_BLEND}|${AW_HID ...

  7. Android用户界面设计:框架布局(转)

    摘要:框架布局是Android开发者组织视图控件最简单和最有效的布局之一.通过本文,你将学到所有关于框架布局的知识,它们主要用来在屏幕上组织特别的或重叠的视图控件.使用得当的话,很多有趣的Androi ...

  8. verilog中的有符号数运算

    verilog中的有符号数运算 http://hi.baidu.com/lixu1113/item/d00dc095f86aed48f142159a verilog中的有符号数运算 有符号数的计算:若 ...

  9. Dubbo与Zookeeper、SpringMVC整合和利用(负载均衡、容错)

    互联网发展,扩大了网站应用程序的大小.传统的垂直应用架构已经无法应付.分布式服务架构和流量计算架构势在必行,Dubbo是一个分布式服务框架.在这样的情况下诞生的.如今核心业务抽取出来.作为独立的服务, ...

  10. 在域信任环境中使用 Team Foundation Server (TFS 2013)

    原文:在域信任环境中使用 Team Foundation Server (TFS 2013) 1. 用户情景和方案: XX公司的大部分软件产品通过软件外包的方式由开发商完成.为加强对软件开发的进度和质 ...