原文: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. Java String 类的 equals 和 ==

    public class Test_String { public static void main(String[] args) { String a = new String("aa&q ...

  2. 使用AppCompat_v7 21.0.0d的几个兼容问题

    1.实现新的ActionBarDrawerToggle动画 ActionBarDrawerToggle使用最新的AppCompat_v7 21会出现一个非常帅的动画.使用方式在Androidstudi ...

  3. .net与Java的WebService互调

    本文记录一下.net与Java是如何进行Web Service的互相调用的. 1.准备工作 MyEclipse 10 JDK 1.6.0_13 Visual Studio 2012 .net fram ...

  4. C++ 堆 和 堆 分析

    [摘要] 堆和栈,即是数据结构,又是分配存储空间的不同方式.在数据结构上.堆是树型层次结构,结点按keyword次序排列,经常使用的堆为二叉堆:栈是一种先进后出的数据结构.在内存分配上的堆和栈,首要差 ...

  5. IE不能上网、有道云笔记不能联网、各种软件主页不能联网解决办法一

    其他的办法我几乎都试过了,读者可以无搜一下,我的问题是,我用Lantern.exe,所以只要打开这个就可以了! 我一直不知道是这个问题,困扰了好久QAQ

  6. TFS:TF30042 数据库已满 处理方法

    原文:TFS:TF30042 数据库已满 处理方法 今天早上,公司打来电话,说TFS(Team Foundation Server)微软源代码管理软件签入不了,报错:TF30042 数据库已满. 经过 ...

  7. 移动端 常见布局CSS3的细节

    结合 Framework7 和ios UI系统,微信weUI,支付宝H5    我们在移动端一些css用法 细节的有了更深的了解: 高斯模糊的显示效果,ios8以上支持,ios8以上0.5px,bac ...

  8. 【源代码】Set集合源代码剖析

    注:下面源代码基于jdk1.7.0_11 Set集合事实上是对Map集合的封装,Map集合存储的是键值对,那么我们将值隐藏,不向外界暴露,这样就形成了Set集合. 相应Map集合的两个非常重要的实现H ...

  9. MVC中使用SignalR

    MVC中使用SignalR打造酷炫实用的即时通讯功能附源码   前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时 ...

  10. Advanced Installer 9.8打包实录

    原文 Advanced Installer 9.8打包实录 主要介绍:(1)创建工程,(2)创建快捷方式及其图标(3)卸载设置 创建工程(.net为例): 工程创建完成....接下来进行简单设置 开始 ...