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

原文: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 的情况下,需要对客户端进行调整.

时间: 2024-12-09 01:24:58

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

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

Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务. 这里我们从一个程序员的视角来观察web service.在传统的程序编码中,存在这各种的函数方法调用.通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法需要的参数P,方法A执行完毕后,返回处理结果R.这种函数或方法调用通常发

Web Service学习笔记

Web Service概述 Web Service的定义 W3C组织对其的定义例如以下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来运行远程系统的请求服务. 这里我们从一个程序猿的视角来观察web service.在传统的程序编码中,存在这各种的函数方法调用.通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法须要的參数P,方法A运行完毕后,返回处理结果R.这样的函数或方法调用

Web Service学习笔记之----JAX-RPC

众所周知,数据科学是这几年才火起来的概念,而应运而生的数据科学家(data scientist)明显缺乏清晰的录取标准和工作内容.此次课程以<星际争霸II>回放文件分析为例,集中在IBM Cloud相关数据分析服务的应用.面对星际游戏爱好者希望提升技能的要求,我们使用IBM Data Science Experience中的jJupyter Notebooks来实现数据的可视化以及对数据进行深度分析,并最终存储到IBM Cloudant中.这是个介绍+动手实践的教程,参会者不仅将和讲师一起在线

Web Service学习之服务端搭建与客户端调用

?工作中用到了Web Service,但是对这块不是很熟悉,决定花时间学习一下,现在记录一下最基本的入门知识点. 使用Java搭建Web Service服务端,使用Python脚本调用接口. 一.Web Service服务端 1.在Eclipse中新建一个Java工程,新建test.TestWebService类 package test; import javax.jws.WebService; import javax.xml.ws.Endpoint; @WebService public 

【web开发学习笔记】Structs2 Result学习笔记(二)动态结果集

Result学习笔记(二) - 动态结果集 动态结果 一定不要忘了为动态结果的保存值设置set get方法 第一部分:代码 //前端 <% String context = request.getContextPath(); %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional

Android Web Service学习总结(一)

最近学习android平台调用webWebService,学习了一篇不错的博客(http://blog.csdn.net/lyq8479/article/details/6428288),可惜是2011年时的方法,而不适合现在android4.0之后的android版本,所以通过一番学习和研究,总结如下. web Service简介 通俗的理解:通过使用WebService,我们能够像调用本地方法一样去调用远程服务器上的方法.我们并不需要关心远程的那个方法是Java写的,还是PHP或C#写的:我

Android Web Service学习总结(二)

上篇文章做好了准备工作,现在就实践(android平台调用web service实现号码归属地查询) 1.    Ksoap2-android简介 在Android平台调用web service需要依赖于第三方类库ksoap2,它是一个SOAP Web service客户端开发包,主要用于资源受限制的Java环境如Applets或J2ME应用程序(CLDC/ CDC/MIDP).在Android平台中我们并不会直接使用ksoap2,而是使用ksoap2 android.KSoap2 Androi

【web开发学习笔记】Structs2 Action学习笔记(二)

action学习笔记2-有关于action method的讨论 Action执行的时候并不一定要执行execute方法,可以在配置文件中配置Action的时候用method=来指定执行哪个方法 也可以在url地址中动态指定(动态方法调用DMI)(推荐) 方法一 <struts> <constant name="struts.devMode" value="true" /> <package name="user" e

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

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