1 示例工程
示例工程源码(.net平台下webservice示例,含静态和动态调用示例)
示例工程源码2(.net动态调用java实现的webservice)
2 简介
站在调用者的角度,表面上WebService就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService 的应用程序叫做客户。
更准确的描述是,WebService是一个平台独立的、松耦合的、自包含的、基于可编程的Web的应用程序,可使用开放的XML标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。
WebService秉承“软件就是服务”的真言,同时顺应分布式计算模式的潮流。而它的存在形式又与以往软件不同。这种组件模式,小巧、单一,对于开发人员来讲,开发成本较低。
WebService不是微软发明的,同样也不属于微软专有。WebService是一个开放的标准,和HTTP、 XML、SOAP一样。他们是一个工业标准而非微软标准,WS-I是为了促进WebService互通性的联盟组织,最初是由IBM和微软所发起,其它的成员包括BEA System、惠普计算机(HP)、甲骨文(Oracle)、英特尔(Intel)和SUN 计算机(Sun Microsystem)。
WebService通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。
WebService要使用两种关键技术:
◆XML
XML (Extensible Markup Language) 扩展型可标记语言。面向短期的临时数据处理、面向万维网络,是Soap的基础。
XML是在web上传送结构化数据的伟大方式,WebService要以一种可靠的自动的方式操作数据,HTML不会满足要求,而XML可以使WebService十分方便的处理数据,它的内容与表示的分离十分理想。
◆SOAP
SOAP (Simple Object Access Protocol) 简单对象存取协议。是XML WebService 的通信协议。当用户通过UDDI找到你的WSDL描述文档后,他通过SOAP调用你建立的Web服务中的一个或多个方法。SOAP是XML文档形式的调用方法的规范,它可以支持不同的底层接口,像HTTP(S)或者SMTP。
SOAP使用XML消息调用远程方法,这样WebService可以通过HTTP协议的post和get方法与远程机器交互,而且,SOAP更加健壮和灵活易用。
WebService使用到的其他技术介绍:
◆WSDL
WSDL (Web Services Description Language) WSDL 文件是一个 XML 文档,用于说明一组 SOAP 消息以及如何交换这些消息。大多数情况下由软件自动生成和使用。
怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web Service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web Service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web Service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web Service生成WSDL文档,又能导入WSDL文档,生成调用相应Web Service的代码。
◆UDDI
UDDI (Universal Description, Discovery, and Integration) 是一个主要针对Web服务供应商和使用者的新项目。在用户能够调用Web服务之前,必须确定这个服务内包含哪些商务方法,找到被调用的接口定义,还要在服务端来编制软件,UDDI是一种根据描述文档来引导系统查找相应服务的机制。UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,编辑,浏览以及查找注册信息。它采用XML格式来封装各种不同类型的数据,并且发送到注册中心或者由注册中心来返回需要的数据。
3 优点
WebService的主要目标是跨平台的可互操作性。为了实现这一目标,WebService 完全基于XML(可扩展标记语言)、XSD(XML Schema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。因此使用WebService有许多优点:
◆跨防火墙的通信
如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。因为客户端和服务器之间通常会有防火墙或者代理服务器。传统的做法是,选择用浏览器作为客户端,写下一大堆ASP页面,把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大,程序很难维护。 要是客户端代码不再如此依赖于HTML表单,客户端的编程就简单多了。如果中间层组件换成WebService的话,就可以从用户界面直接调用中间层组件,从而省掉建立ASP页面的那一步。要调用WebService,可以直接使用Microsoft SOAP Toolkit或.net这样的SOAP客户端,也可以使用自己开发的SOAP客户端,然后把它和应用程序连接起来。不仅缩短了开发周期,还减少了代码复杂度,并能够增强应用程序的可维护性。同时,应用程序也不再需要在每次调用中间层组件时,都跳转到相应的“结果页”。
◆应用程序集成
企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发力量。应用程序经常需要从运行的一台主机上的程序中获取数据;或者把数据发送到主机或其它平台应用程序中去。即使在同一个平台上,不同软件厂商生产的各种软件也常常需要集成起来。通过WebService,应用程序可以用标准的方法把功能和数据“暴露”出来,供其它应用程序使用。XML Web Services 提供了在松耦合环境中使用标准协议(HTTP、XML、SOAP 和 WSDL)交换消息的能力。消息可以是结构化的、带类型的,也可以是松散定义的。
◆B2B的集成
B2B 指的是Business to Business,as in businesses doing business with other businesses,商家(泛指企业)对商家的电子商务,即企业与企业之间通过互联网进行产品、服务及信息的交换。通俗的说法是指进行电子商务交易的供需双方都是商家(或企业、公司),她们使用了Internet的技术或各种商务网络平台,完成商务交易的过程。WebService是B2B集成成功的关键。通过WebService,公司可以只需把关键的商务应用“暴露”给指定的供应商和客户,就可以了,WebService运行在Internet上,在世界任何地方都可轻易实现,其运行成本就相对较低。WebService只是B2B集成的一个关键部分,还需要许多其它的部分才能实现集成。 用WebService来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把商务逻辑“暴露”出来,成为WebService,就可以让任何指定的合作伙伴调用这些商务逻辑,而不管他们的系统在什么平台上运行,使用什么开发语言。这样就大大减少了花在B2B集成上的时间和成本。
◆软件和数据重用
WebService在允许重用代码的同时,可以重用代码背后的数据。使用WebService,再也不必像以前那样,要先从第三方购买、安装软件组件,再从应用程序中调用这些组件;只需要直接调用远端的WebService就可以了。另一种软件重用的情况是,把好几个应用程序的功能集成起来,通过WebService“暴露”出来,就可以非常容易地把所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。 可以在应用程序中使用第三方的WebService 提供的功能,也可以把自己的应用程序功能通过WebService 提供给别人。两种情况下,都可以重用代码和代码背后的数据。
4 创建WebService
WebService方法可返回类型:int, string, double, bool, DataTable, DataSet, ArraList, List
WebService方法可传递参数对象:int, string, double, bool, List
WebService方法原型示例:
[WebMethod]
public string FunctionName(string str)
{}
特别注意:
◆不能有方法重载,方法名必须唯一,否则不能添加Web引用;
◆方法不能加static修饰,否则引用中找不到需要的方法;
◆方法前一定要有[WebMethod] ,否则引用中找不到需要的方法;
◆返回类型是DataTable的时候,DataTable一定要有名字,否则程序运行中报错;
.net平台内建了对WebService的支持,包括WebService的构建和使用。与其它开发平台不同,使用.net平台,你不需要其他的工具或者SDK就可以完成WebService的开发了。.net Framework本身就全面支持WebService,包括服务器端的请求处理器和对客户端发送和接受SOAP消息的支持。下来我们就一步一步的用Microsoft Visual Studio 2008(后面简称VS 2008)创建和使用一个简单的示例WebService。
打开VS2008,依次选择菜单”File” ->”New”->”Project…”->”ASP.NET Web Service Application”,输入工程名称并选择存放路径,确定后创建一个新的WebService工程。
示例代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Services; 6 7 namespace WebServiceExample 8 { 9 ///10 /// Summary description for Service1 11 /// 12 [WebService(Namespace = "http://tempuri.org/")] 13 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 14 [System.ComponentModel.ToolboxItem(false)] 15 // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 16 // [System.Web.Script.Services.ScriptService] 17 public class Service1 : System.Web.Services.WebService 18 { 19 20 [WebMethod] 21 public string HelloWorld() 22 { 23 return "Hello World"; 24 } 25 [WebMethod] 26 public int Add(int a, int b) 27 { 28 return a + b; 29 } 30 } 31 }
WebService的发布相关介绍在本篇文章中不进行描述。用户可直接在VS2008中运行,运行结果如下图所示:
WebService中WebMethod的各种特性:
属性 |
功能 |
示例 |
BufferResponse |
设置为True时,XML Web服务的响应就保存在内存中,并发送为一个完整的包。如果该属性设置为False,则响应在服务器上构造的同时,会发送给客户机。 |
[WebMethod(BufferResponse=true)] |
CacheDuration |
指定响应在系统的高速缓存中的保存时间(秒),默认值为0,表示禁用高速缓存。把XML Web服务的响应放在高速缓存中,会提高Web服务的性能。 |
[WebMethod(BufferResponse=true,CacheDuration=30)] |
Description |
对在XML Web服务的测试页面上显示的Web Method应用文本的描述。 |
[WebMethod(Description="该方法用于获取一个简单的字符串")] |
EnableSession |
设置为True时,会激活Web Method的会话状态,其默认值为False。 |
[WebMethod(EnableSession=true)] |
MessageName |
给Method指定一个唯一的名称,如果要使用重载的Web Method,则必须指定。 |
[WebMethod(MessageName="Method1")] |
TransactionOption |
为Web Method指定事务的支持,其默认值为Disbled。如果Web Method是启动事务的根对象,Web服务就可以用另一个需要事务处理的WebMethod参与事务处理。其值可以是NotSupported、Supported、Required和RequiresNew。 |
[WebMethod(TransactionOption=System.EnterpriseServices.TransactionOption.Sup |
5 调用WebService
5.1 静态调用
静态调用的方式是通过“Add Service Reference...”创建客户端代理类。这种方式让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却将提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。
用户在“Solution Explorer”窗口中,右键点击工程,选择“Add Service Reference...”,进入如下界面:
将要调用的 WebService的URL地址复制到 “Add Service Reference” 窗口 的“Address” 位置。在“Namespace”里输入我们自己定义的名字,这里我叫它WebServiceTest,点一下按钮“Go”,等如下图以后,点击“OK”,工具就会自动把这个WebService添加到项目中。
添加WebService完成后,“Solution Explorer”窗体如下图所示,可以看到WebServiceTest已经添加到工程中。
用户在客户端调用时,首先生成WebService客户端对象,然后通过生成的对象可以向调用本地方法一样调用WebService所提供的方法。
1 //生成WebService客户端对象 2 WindowsFormsApplicationStatic.WebServiceTest.Service1SoapClient client = 3 new WindowsFormsApplicationStatic.WebServiceTest.Service1SoapClient(); 4 5 this.label1.Text = client.HelloWorld();
5.2 动态调用
在某些情况下我们需要在程序运行期间动态调用一个服务。在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西。动态调用有动态调用 WebService、生成客户端代理程序集文件、生成客户端代理类源代码3种方式。
动态调用的具体步骤为:
1)从目标 URL 下载 WSDL 数据;
2)使用 ServiceDescription 创建和格式化 WSDL 文档文件;
3)使用 ServiceDescriptionImporter 创建客户端代理类;
4)使用 CodeDom 动态创建客户端代理类程序集。
5)利用反射调用相关 WebService 方法;
【注意】.net动态调用java创建的WebService,与.net动态调用.net创建的WebService,在步骤2)的代码实现上略有不同。具体请参考第6章的描述。
上述步骤需要引用如下四个名称空间:
//WebService的描述
using System.Web.Services.Description;
//根据描述动态生成代码并动态编译获取程序集
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
上述几个名称空间中包括如下几个重要的类:
命名空间System.Web.Services.Description下:ServiceDescription、ServiceDescriptionImporter(通过描述生成客户端代理类,特别注意其中的Style)。XML Web services 的接口通常由 Web 服务描述语言 (WSDL) 文件来说明。例如,若要获取有关使用 http://localhost/service.asmx 处公开的 ASP.NET 的 Web 服务的 WSDL 说明,只需导航到 http://localhost/service.asmx?WSDL。使用 ServiceDescriptionImporter 类可以方便地将 WSDL 说明中包含的信息导入到 System.CodeDom.CodeCompileUnit 对象。通过调整 Style 参数的值,可以指示 ServiceDescriptionImporter 实例生成客户端代理类(通过透明调用该类可提供 Web 服务的功能)或生成抽象类(该类封装 Web 服务的功能而不实现该功能)。如果将 Style 属性设置为 Client,则 ServiceDescriptionImporter 生成客户端代理类,通过调用这些类来提供说明的 Web 服务的功能。如果将 Style 属性设置为 Server,则 ServiceDescriptionImporter 实例生成抽象类,这些类表示所说明的 XML Web services 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
命名空间System.CodeDom下:CodedomUnit。它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WebService的描述代码写入该类,以作动态编译用。
命名空间System.CodeDom.Compiler下:CodedomProvider 、CompilerResults、CompiledAssembly。CodedomProvider用于创建和检索代码生成器和代码编译器的实例,我们主要用到其实现子类CShareCodeProvider,可以直接用CShareCodeProvider provider=new CShareCodeProvider()来生成,或者用CodedomProvider.CreateProvider("CSharp")来生成。ICodeCompiler //用于编译基于 System.CodeDom 的源代码表示形式。 它通过CodedomProvider的CreateCompiler()方法来生成编译结果。CompilerResults表示从编译器返回的编译结果。它由ICodeCompiler根据指定的编译器设置从指定的 CodeCompileUnit 所包含的 System.CodeDom 树中编译程序集并返回。CompiledAssembly 属性指示编译的程序集。
方式一:动态调用 WebService
客户端动态调用WebService的示例代码如下所示:
1 //使用 WebClient 下载 WSDL 信息。 2 WebClient web = new WebClient(); 3 Stream stream = web.OpenRead(“http://localhost:52773/Service1.asmx?WSDL”); 4 5 //创建和格式化 WSDL 文档。 6 ServiceDescription description = ServiceDescription.Read(stream); 7 8 //创建客户端代理类。 9 ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); 10 11 importer.ProtocolName = "Soap"; 12 importer.Style = ServiceDescriptionImportStyle.Client; 13 importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 14 15 // 添加 WSDL 文档。 16 importer.AddServiceDescription(description, null, null); 17 18 //使用 CodeDom 编译客户端代理类。 19 CodeNamespace nmspace = new CodeNamespace(); 20 CodeCompileUnit unit = new CodeCompileUnit(); 21 unit.Namespaces.Add(nmspace); 22 23 ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 24 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); 25 26 CompilerParameters parameter = new CompilerParameters(); 27 parameter.GenerateExecutable = false; 28 parameter.GenerateInMemory = true; 29 parameter.ReferencedAssemblies.Add("System.dll"); 30 parameter.ReferencedAssemblies.Add("System.XML.dll"); 31 parameter.ReferencedAssemblies.Add("System.Web.Services.dll"); 32 parameter.ReferencedAssemblies.Add("System.Data.dll"); 33 34 CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); 35 36 // 使用 Reflection 调用 WebService。 37 if (!result.Errors.HasErrors) 38 { 39 Assembly asm = result.CompiledAssembly; 40 Type asmType = asm.GetType("Service1"); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。 41 42 Object o = Activator.CreateInstance(asmType); 43 MethodInfo method = asmType.GetMethod("HelloWorld"); 44 this.label1.Text = (string) method.Invoke(o, null); 45 }
方式二:生成客户端代理程序集文件
上面的代码通过在内存中创建动态程序集的方式完成了动态调用过程。如果我们希望将客户端代理类生成程序集文件保存到硬盘,则可以进行如下修改。生成程序集文件后,我们可以通过 Assembly.LoadFrom() 载入并进行反射调用。对于需要多次调用的系统,要比每次生成动态程序集效率高出很多。
1 //使用 WebClient 下载 WSDL 信息。 2 WebClient web = new WebClient(); 3 Stream stream = web.OpenRead(“http://localhost:52773/Service1.asmx?WSDL”); 4 5 //创建和格式化 WSDL 文档。 6 ServiceDescription description = ServiceDescription.Read(stream); 7 8 //创建客户端代理类。 9 ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); 10 11 importer.ProtocolName = "Soap"; 12 importer.Style = ServiceDescriptionImportStyle.Client; 13 importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 14 15 // 添加 WSDL 文档。 16 importer.AddServiceDescription(description, null, null); 17 18 //使用 CodeDom 编译客户端代理类。 19 CodeNamespace nmspace = new CodeNamespace(); 20 CodeCompileUnit unit = new CodeCompileUnit(); 21 unit.Namespaces.Add(nmspace); 22 23 ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 24 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); 25 26 CompilerParameters parameter = new CompilerParameters(); 27 parameter.GenerateExecutable = false; 28 parameter.OutputAssembly = "WebServiceTest.dll"; // 可以指定你所需的任何文件名。 29 parameter.ReferencedAssemblies.Add("System.dll"); 30 parameter.ReferencedAssemblies.Add("System.XML.dll"); 31 parameter.ReferencedAssemblies.Add("System.Web.Services.dll"); 32 parameter.ReferencedAssemblies.Add("System.Data.dll"); 33 34 CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); 35 36 // 使用 Reflection 调用 WebService。 37 if (!result.Errors.HasErrors) 38 { 39 Assembly asm = Assembly.LoadFrom("WebServiceTest.dll"); 40 Type asmType = asm.GetType("Service1"); 41 42 Object o = Activator.CreateInstance(asmType); 43 MethodInfo method = asmType.GetMethod("HelloWorld"); 44 this.label1.Text = (string) method.Invoke(o, null); 45 }
方式三:生成客户端代理类源代码
代码如下:
1 //使用 WebClient 下载 WSDL 信息。 2 string str = ConfigurationManager.AppSettings["WebServiceUrl"]; 3 WebClient web = new WebClient(); 4 Stream stream = web.OpenRead(str); 5 6 //创建和格式化 WSDL 文档。 7 ServiceDescription description = ServiceDescription.Read(stream); 8 9 //创建客户端代理类。 10 ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); 11 12 importer.ProtocolName = "Soap"; 13 importer.Style = ServiceDescriptionImportStyle.Client; 14 importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 15 16 // 添加 WSDL 文档。 17 importer.AddServiceDescription(description, null, null); 18 19 //使用 CodeDom 编译客户端代理类。 20 CodeNamespace nmspace = new CodeNamespace(); 21 CodeCompileUnit unit = new CodeCompileUnit(); 22 unit.Namespaces.Add(nmspace); 23 24 ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 25 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); 26 27 // 保存源代码到文件。 28 TextWriter writer = File.CreateText("WebServiceTest.cs"); // 指定你所需的源代码文件名。 29 provider.GenerateCodeFromCompileUnit(unit, writer, null); 30 writer.Flush(); 31 writer.Close(); 32 33 //启动进程编译源文件 34 //指定参数 35 ProcessStartInfo psi = new ProcessStartInfo(); 36 //启动cmd.exe 37 psi.FileName = "cmd.exe"; 38 //cmd.exe的参数,/c-close,完成后关闭;后为参数,指定cmd.exe使用csc来编译刚才生成的源文件 39 string compileString = "/c C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\csc.exe /optimize+ /target:library {0}.cs"; 40 psi.Arguments = String.Format(compileString, "WebServiceTest"); 41 //运行时的风格-隐藏 42 psi.WindowStyle = ProcessWindowStyle.Hidden; 43 44 //启动进程 45 Process proc = Process.Start(psi); 46 //指定当前在此进程退出前等待 47 proc.WaitForExit(); 48 49 // 使用 Reflection 调用 WebService。 50 Assembly asm = Assembly.LoadFrom("WebServiceTest.dll"); 51 Type asmType = asm.GetType("Service1"); 52 53 Object o = Activator.CreateInstance(asmType); 54 MethodInfo method = asmType.GetMethod("HelloWorld"); 55 this.label1.Text = (string) method.Invoke(o, null);
6 .net动态调用java实现的WebService
.net实现的WebService和java实现的WebService的WSDL不完全相同,因此在解析的时候也要相应作出改变。
.net动态调用java实现的WebService时,使用如下两种方式将服务描述导入到服务描述导入器中。
方式一:从URL将WSDL读取到XmlTextReader中,服务描述从XmlTextReader中读取。
WebRequest request = WebRequest.Create(wsdlUrl); WebResponse result = request.GetResponse(); Stream stream = result.GetResponseStream(); Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); StreamReader reader = new StreamReader(stream, encode); wsdlSource = reader.ReadToEnd(); StringReader wsdlStringReader = new StringReader(wsdlSource); XmlTextReader textReader = new XmlTextReader(wsdlStringReader); ServiceDescription description = ServiceDescription.Read(textReader); textReader.Close(); // WSDL service description importer CodeNamespace codeNamespace = new CodeNamespace("WSDataAccess.DynamicProxy"); this.sdi = new ServiceDescriptionImporter(); this.sdi.AddServiceDescription(description, null, null);
方式二:通过DiscoveryClientProtocol读取服务描述。
DiscoveryClientProtocol dcp = new DiscoveryClientProtocol(); dcp.DiscoverAny(baseWSDLUrl);//webservice的URL(不包含 ”?wsdl”) dcp.ResolveAll(); foreach (object osd in dcp.Documents.Values) { if (osd is ServiceDescription) sdi.AddServiceDescription((ServiceDescription)osd, null, null); if (osd is XmlSchema) sdi.Schemas.Add((XmlSchema)osd); }