[转]Web Service开发实用指南

Web Service平台是一套标准,它定义了应用程序如何在Web上实现交互性操作。你可以用你喜欢的任何语言,在任何平台上编写Web Service,只要我们可以通过Web Service标准对这些服务进行查询和访问即可。

  本文选用VB.NET平台,向你讲述Web Service开发的方法与技巧。

  一、Web Service平台的组成技术
  1.什么是Web Service
  从表面上看,Web Service是一个应用程序,一个能够通过Web进行调用的API(Application Programming Interface,应用编程接口)。即是说,你能够用编程的方法,通过Web调用,来实现某个功能的应用程序。

  从深层次上看,Web Service是一种新的Web应用程序分支,它们是自包含、自描述、模块化的应用,可以在网络(通常为Web)中被描述、发布、查找以及通过Web来调用。

  Web Service是基于网络的、分布式的模块化组件,它执行特定的任务,遵守具体的技术规范,这些规范使得Web Service能与其他兼容的组件进行交互操作。它可以使用标准的Internet协议,将功能体现在Internet和企业内部网上。

  2.Web Service平台的组成技术
  通常情况下,Web Service由以下3个主要技术部分组成:

  (1)XML和XSD

  XML (Extensible Markup Language,可扩展的标记语言)是Web Service平台中表示数据的基本格式。XML解决了数据表示的问题,但它没有定义标准的数据类型,更没有定义怎样去扩展数据类型。例如,整形数到底代表什么?16位,32位,还是64位?这些细节对实现交互操作都是很重要的。W3C(万维网联盟)制定的XML Schema(XSD)即是专门解决这个问题的一套标准。它定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。Web Service平台就是用XSD作为其数据类型系统的。当你用某种编程语言(如VB.NET或C#)来编写一个Web Service应用程序时,为了符合Web Service标准,所有你使用的数据类型都必须被转换为XSD类型。

  (2)SOAP

  Web Service应用程序编写好以后,我们需要去调用它,SOAP(Simple Object Access Protocol,简单对象访问协议)提供了标准的RPC(远程过程调用)方法来调用Web Service。SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP。SOAP基于XML和XSD。

  (3)WSDL

  WSDL(Web Service Description Language,Web服务说明语言)是一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。因为其基于XML,所以WSDL既是机器可阅读的,又是开发者可阅读的。一些最新的开发工具既能根据你的Web Service生成WSDL文档,又能导入WSDL文档,生成调用相应的Web Service代码。

  3.Web Service工作流程
  Web Service的工作流程如图1所示。

 

  在使用Web Service时,包括3个阶段的通信,在图1中,列出了3个阶段的通信流程。第1阶段的通信被称为发现阶段(Discover),其主要作用是确定在服务器上有哪些服务。

  经过发现阶段我们一般可以确定服务器一共提供了哪些服务。在使用这些服务之前我们还必须知道这些服务支持什么样的界面。所以Web Service第2阶段的通信就是发送请求获得Web Service描述语言WSDL。

  第3阶段的通信主要是向Web Service服务器发送信息服务请求,并等待服务器的应答。

  二、.NET中关于Web Service的技术要素
  利用.NET中专为Web Service开发的类接口,我们可以轻松地创建一个Web Service程序。下面介绍一些主要的技术要素。

  1.Web Service 处理指令
  Web Service处理指令为ASP.NET环境提供了必要的信息,如实现XML Web Services功能的类。以下是.asmx文件中Web Service处理指令的示例:

  <%@ WebService Language="vb" Codebehind="Service1.asmx.vb "Class="WebService1.Service1" %>

  其中,Language属性指示开发XML Web Services所使用的编程语言。可以使用任何与.NET兼容的语言(如VB.NET或C#)来创建XML Web Services。与.asmx页关联的支持代码文件由Codebehind属性来指示。Class属性指示支持代码文件中用来实现XML Web Services功能的类。

  注意:要在.NET的“解决方案资源管理器”中查看.asmx文件的内容,请用右键单击.asmx文件,然后单击“打开方式”命令。在“打开方式”对话框中,选择“源代码 [文本] 编辑器”选项,然后单击“打开”按钮即可。

  2.System.Web.Services.WebService类
  System.Web.Services.WebService类定义了XML Web Services的可选基类,并提供了直接访问常见ASP.NET对象(如应用程序和会话状态的对象)的权限。默认情况下,使用Visual Studio.NET以托管代码的形式创建的XML Web Services继承此类。XML Web Services可继承此类以获得访问ASP.NET固有对象(如Request和Session)的权限。

  如果XML Web Services没有继承此类,也可System.Web.HttpContext.Current访问ASP.NET固有对象。实现XML Web Services的类必须是公共的,且必须有一个公共的默认构造函数(不带参数的构造函数)。这样,ASP.NET就能够创建XML Web Services类的实例以处理传入的XML Web Services请求。

  3.WebService属性
  每个XML Web Services都需要唯一的命名空间,它可使客户端应用程序区分出可能使用相同方法名称的XML Web Services。在Visual Studio .NET中创建的XML Web Services 的默认命名空间是“http://tempuri.org”。尽管命名空间类似于典型的URL(统一资源标识符),但在Web浏览器中是不能查看的,它只是一个唯一标识符。WebService属性主要包括以下几种属性:

  (1)Description属性

  此属性的值包含描述性消息,此消息将在XML Web Services的说明文件(例如服务说明和服务帮助页)生成后显示给XML Web Services的潜在用户。

  (2)Name属性

  此属性的值包含XML Web Services的名称。默认情况下,该值是实现XML Web Services的类的名称。Name属性标识XML Web Services的XML限定名称的本地部分。Name属性也用于在服务帮助页上显示XML Web Services的名称。

  (3)Namespace属性

  此属性的值包含XML Web Services的默认命名空间。XML命名空间提供了在XML文档中创建名称的方法,该名称可由URL标识。使用XML命名空间,可以唯一标识XML文档中的元素或属性。因而,在XML Web Services的服务说明中,Namespace被用作与XML Web Services直接相关的XML元素的默认命名空间。如果不指定命名空间,就使用默认命名空间“http://tempuri.org”。

  以下示例代码说明了WebService属性的用法:

  <WebService(Namespace:="http://MyServer/MyWebServices/", _

   Description:="此处可以放一些描述性文字。",

   Name:="MyFavoritesService")> _

  Public Class Service1

   Inherits System.Web.Services.WebService

   ' 实现代码

  End Class

  4.WebMethod属性
  以托管代码创建XML Web Services时,通过在Public方法声明之前放置WebMethod属性可以指定在XML Web Services中可用的方法。Private方法不能充当XML Web Services的入口点,尽管它们可以采用相同的类,并且XML Web Services代码可以调用它们。WebMethod属性必须应用到可用作XML Web Services一部分的每种公共方法中。

  WebMethod属性包含配置XML Web Services行为的几个属性。例如,可以使用此属性在相关服务帮助页提供一个简短说明。WebMethod属性提供以下属性:

  (1)BufferResponse属性

  当此属性设置为True(默认设置)时,ASP.NET将响应向下发送到客户端之前先缓存整个响应。缓存是一种非常有效的方法,可以通过减少辅助进程和Internet信息服务(IIS)进程之间的通信来提高性能。当设置为False时,ASP.NET会将响应缓存在16KB的区块中。通常,只有在不想一次将响应的全部内容都缓存在内存中时,才将此属性设置为False。例如,正在写一个多项流出数据库的集合。除非另行指定,否则默认值为True。

  (2)CacheDuration属性

  此属性的值指定ASP.NET缓存每个唯一参数设置结果所需的秒数。除非另行指定,否则默认值为0,此设置将禁用结果缓存。

  (3)Description属性

  此属性的值提供了对XML Web Services方法的说明,显示于服务帮助页中。除非另行指定,否则默认值为空字符串。

  (4)EnableSession属性

  当此属性设置为False(默认设置)时,ASP.NET将无法访问XML Web Services方法的会话状态。当设置为True时,XML Web Services可以直接从HttpContext.Current.Session访问会话状态集合;在继承了WebService基类的情况下,也可以使用WebService.Session属性进行访问。

  (5)MessageName属性

  此属性的值使XML Web Services能够使用别名来唯一标识重载的方法。除非另行指定,否则默认值为方法名。当为MessageName指定值后,结果SOAP消息会反映出此名称而不是实际的方法名。

  (6)TransactionOption属性

  此属性的值指定XML Web Services方法是否可以作为事务的根对象。虽然可以将TransactionOption属性设置为TransactionOption枚举类型的任意值,但是XML Web Services方法仅有两种可能行为:它不参与事务(Disabled、NotSupported和Supported),或是创建新事务(Required和RequiresNew)。除非另行指定,否则默认值为TransactionOption.Disabled。要使用此属性,需要向System.EnterpriseServices.dll添加一个引用。此命名空间包含的方法和属性,提供了可在COM+服务中找到的分布式事务模型。System.EnterpriseServices.ContextUtil类允许你使用SetAbort或SetComplete方法设置该事务。

  以下示例代码说明了WebMethod属性的用法:

  Public Class Service1

   Inherits System.Web.Services.WebService

   <WebMethod(BufferResponse:=False, _

       CacheDuration:=60, _

       Description:="一些描述性的文字",

       MessageName:="RetrieveData")> _

   Public Function GetBigChunkOfData()As DataSet

   '实现代码

   End Function

  End Class

  5.XML Web Services发现
  XML Web Services发现是对XML Web Services说明进行定位和询问的过程,是访问XML Web Services的基本步骤。通过发现进程,XML Web Services客户端能够在设计阶段了解某个XML Web Services是否存在,它的功能如何,以及如何正确与它进行交互操作。

  然而,实现XML Web Services的Web站点不需要支持该发现进程,而是由另一个站点负责说明服务(如XML Web Services目录)。另外,可能没有一个公开的方法可用来查找服务,例如在创建专用服务时。XML Web Services发现主要包括以下内容:

  (1)静态发现(.disco)

  可以通过发布.disco文件(一个XML文档,包含指向其他发现文档、XSD方案和服务说明的链接)来启用XML Web Services的程序发现。使用ASP.NET自动创建的XML Web Services能够提供生成的发现文档。例如,要访问名为Service1.asmx(本地计算机中WebService1项目的一部分)的XML Web Services发现文档,可使用以下URL:

  http://localhost/WebService1/Service1.asmx?DISCO

  以下示例显示了发现文档的结构:

  <?xml version="1.0"?>

  <disco:discovery xmlns:disco="http://schemas.xmlsoap.org/disco"

  xmlns:wsdl="http://schemas.xmlsoap.org/disco/wsdl">

  <wsdl:contractRef ref="http://MyWebServer/UserName.asmx?WSDL"/

  </disco:discovery>

  注意:发现文档是一个元素容器,通常包含提供XML Web Services发现信息的资源链接(URL)。如果URL是相对的,则假定它们是相对于发现文档的位置。

  (2)动态发现(.vsdisco)

  动态发现是ASP.NET通过开发Web服务器上的文件夹层次结构执行迭代搜索以查找可用的XML Web Services的过程。动态发现(.vsdisco)文件是基于XML的文件,可以包含0或多个节点。每个节点包含一个path属性,path属性包含指向子文件夹(动态发现进程不应搜索的子文件夹)的相对路径。以下是.vsdisco示例文件:

  <?xml version="1.0" encoding="utf-8"?>

  <dynamicDiscovery xmlns="urn:schemas-dynamicdiscovery:disco.2003-10-17">

     <exclude path="_vti_cnf"/>

     <exclude path="_vti_pvt"/>

     <exclude path="_vti_log"/>

     <exclude path="_vti_script"/>

     <exclude path="_vti_txt"/>

     <exclude path="Web References"/>

  </dynamicDiscovery>

  当启用了动态发现的Web服务器请求.vsdisco文件时,对于已通过动态发现进程进行定位的每个Web Service,都会返回一个包含Web Service发现信息的发现文档。

  默认情况下,web.config中禁用了动态发现。要控制哪些XML Web Services客户端可以发现服务,应该在开发Web服务器上只使用动态发现。当向生产Web服务器部署XML Web Services时,应为那些希望客户端能够发现的XML Web Services创建并发布一个静态发现文件(.disco)。

  三、创建Web Service程序的详细步骤
  对.NET来讲,Web Service其实就是一个服务器的类。这个类的一种方法以一种特殊的方式标记以让.NET可以知道在服务上公布哪些方法。读者可以通过以下简单的程序来进一步了解.NET中关于Web Service的内部机制。

  1.创建步骤
  在Visual Studio.NET中创建一个基于ASP.NET Web服务的工程。定义工程名为DemoService。

  完成这一步后,会创建一个新的Web站点,以及该站点的一个新网页Service1.asmx。该页面表示一个服务,而一个Web Service工程可以包含许多个不同的服务。同时生成的还有Global.asax和Web.config两个文件,这两个文件用来配置Web环境。

  在“解决方案资源管理器”中右键单击Service1.asmx,选择“查看代码”命令,这时我们可以看到Web Service中放置了一个“Hello World”的示例方法。如图2所示。

 

  下文中我们将以这个示例为基础,对其进行扩充。

  直接运行该工程,运行结果如图3所示。

 

  点击上图中的“HelloWord”链接,会打开另外一个运行方法页面。单击“调用”按钮,从新打开的窗口中我们可以看到从服务器返回的SOAP响应。

  <?xml version="1.0"encoding="utf-8"?>

  <string xmlns="http://tempuri.org/"> Hello World</string>

  代码说明:

  在Web Service中,每个.asmx页面后面都有一个类。这个类就是HelloWorld方法所在的,从图2的显示代码:

  Public Class Service1

   Inherits System.Web.Services.WebService

  我们可以发现,该类继承于System.Web.Services.WebService。此类用于给出用户在Internet Explorer中单击的页面并调用HelloWorld方法。WebMethod属性标记用来表示方法是作用于Web Service类的。

  2.添加更多的方法
  现在让我们为DemoService构建一些新的方法用以说明Web Service的实际工作。

  打开Service1.asmx的代码编辑器,在HelloWorld方法中编写以下代码:

  <WebMethod()> Public Function NewTest(ByVal number As Double)As Double

   Return Math.Sqrt(number)

  End Function

  说明:此方法用以求一个数的平方根。

  编译后再次运行该程序。运行结果如图4所示:

 

  单击“NewTest”链接。如图5所示。

 

  在“number”框中填入数字“121”,单击“调用”按钮,SOAP响应信息如下所示:

  <?xml version="1.0"encoding="utf-8"?>

  <double xmlns="http://tempuri.org/">11</double>

  通过上面的演示我们不难发现,构建一个简单的Web Service并不复杂。下面我们将通过一个具体的实例来进一步介绍如何构建Web Service。

  四、实例解析──用Web Service比较两个数的大小
  通过前面的介绍我们已经知道了如何创建Web Service的服务端。本例的重点在于如何访问Web Service,即用户端如何与Web Service互动访问。

  1.实例详解
  创建Web Service 工程名为“TheMax”。由于创建的方法与步骤上文中已有介绍。实例中直接给出核心代码。

  <WebMethod()>Public Function MaxNum(ByVal number1 As Integer,ByVal number2 As Integer)As Integer

  Dim number3 As Integer

  If number1 - number2 < 0 Then number3 = number1 Else number3 = number2

  MaxNum = number3

  End Function

  运行此程序结果如图6所示:

 

  分别在number1、number2框中填入两个数,例如,87、98,单击“调用”按钮,得到如下结果:

  <?xml version="1.0"encoding="utf-8"?>

  <int xmlns="http://tempuri.org/">98</int>

  完成以上步骤后,我们的Web Service即构建成功。

  2.Web Service访问
  通常情况下,访问Web Service有两个方式,即Windows应用程序访问和Web程序调用访问。

  创建一个Windows应用程序,并命名为“TheMax”,设计程序界面如图7所示。

 

  现在,让我们来建立“Web引用”。这是最重要也是最关键的一步。在“解决方案资源管理器”中,右键单击工程名TheMax,选择“添加Web引用”命令。在地址栏中输入访问Web Servie的URL:http://localhost/themax/service1.asmx

  如果“Web引用”建立正确,在“解决方案资源管理器”的“引用”中会自动生成一个Web References文件夹。该文件夹下面有一个地球仪图标,图标后面就是Web Service服务器名称。双击命令按钮,输入以下代码:

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)Handles Button1.Click

   Dim Maxnum As String

   Dim TheMax As New localhost.Service1()

   Dim number1 As Integer = Val(TextBox1.Text)

   Dim number2 As Integer = Val(TextBox2.Text)

   Maxnum = TheMax.MaxNum(number1, number2)

   Label3.Text = "最大的一个数是:" & Maxnum

  End Sub

  编译并运行程序。运行结果如图8所示。

 

  Windows应用程序在调用Web Service程序时,必须在本地保留WSDL的文件备份,以用来描述调用的Web Service程序。通过WSDL文件所提供的信息,Visual Studio.NET的IDE可以验证传到Web Service程序的参数类型是否正确,以及返回给Windows应用程序的数据类型是否匹配。

  3.Web程序调用访问
  Web应用程序天生就具有访问Web Service程序的功能。因为这两种程序都是依靠Internet来进行通信的。下面,我们介绍Web程序如何访问Web Service的。

  创建一个Web应用程序工程,并命名为WebTheMax。单击Web Form,将PageLayout属性设为“gridlayout”。按图9所示设计程序界面。

 

  增加Web引用,方法与Windows应用程序访问方式一样。然后双击“进行比较”按钮,输入以下代码:

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

   Dim Maxnum As String

   Dim TheMax As New localhost.Service1()

   Dim number1 As Integer = Val(TextBox1.Text)

   Dim number2 As Integer = Val(TextBox2.Text)

   Maxnum = TheMax.MaxNum(number1, number2)

   Label3.Text = Maxnum

  End Sub

  编译并运行程序。在两个框中填入两个数45、54,点击“进行比较”按钮即可得到相应的结果。

  通过对两种Web Service访问方式的介绍我们不难发现实现这两种方式的方法与步骤基本是一样的。核心内容就在于“增加Web引用”。只有正确建立客户端与服务端的链接,才能顺利的进行数取交换。这也是构建Web Service程序的重中之重。

  五、实例解析──创建文件夹查看器
  通过上面的实例介绍,我们基本了解了一个Web Service程序的创建步骤及访问方法。现在,我们将通过一个相对比较复杂的Web Service程序来进一步介绍Web Service服务器的构建方法。

  本实例达到的目的:构建一个文件夹查看器,列出指定目录中的所有子文件夹。

  我们首先给出实例代码,然后再进行详细分析。

  创建一个新的ASP.NET Web服务工程,并命名为PictureService。

  在服务根目录,即C:\inetpub\wwwroot\PictureService文件夹下新建一个“pictures”文件夹,并在该文件夹下新建两个子文件夹分别命名为myPicture、youPicture。

  在Service1.asmx代码编辑器中输入以下代码:

  Imports System.Web.Services

  Imports System.IO

  自动生成代码。

  Public ReadOnly Property PictureFolerPath() As String

    Get

     Dim asmxPath As String, picturePath As String

     asmxPath = Server.MapPath(Context.Request.ServerVariables.Item("script_name"))

     Dim n As Integer

     For n = asmxPath.Length - 1 To n Step -1

      If asmxPath.Chars(n) = "\"c Then

      Dim serverPath As String = asmxPath.Substring(0, n)

      picturePath = serverPath & "\pictures"

       Exit For

      End If

     Next

     Return picturePath

    End Get

  End Property

  Public ReadOnly Property PictureFolder() As DirectoryInfo

    Get

     Return New DirectoryInfo(PictureFolerPath)

    End Get

    End Property

     Public Function GetPictureFolders() As String()

      Dim pictureFolder As DirectoryInfo = Me.PictureFolder

      Dim pictureSubFolders() As DirectoryInfo = pictureFolder.GetDirectories()

      Dim folderName(pictureSubFolders.Length - 1) As String

      Dim pictureSubFolder As DirectoryInfo, index As Integer

      For Each pictureSubFolder In pictureSubFolders

       folderName(index) = pictureSubFolder.Name

         index += 1

      Next

       Return folderName

    End Function

  End Class

  运行程序,结果如下:

  <?xml version="1.0" encoding="utf-8" ?>

  - <ArrayOfString mlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">

   <string>myPicture</string>

   <string>youPicture</string>

   </ArrayOfString>

  下面我们来分析上述代码:

  要列举出指定文件夹下的所有子文件夹,首先就要得到该文件的完整路径。本例中我们首先创建了一个PictureFolderPath属性,用来得到支持整个服务的Service.asmx文件的完整路径C:\inetpub\wwwroot\PictureService\Servcie1.asmx。程序中我们使用以下代码来实现这点:

  Dim asmxPath As String, picturePath As String

  asmxPath = Server.MapPath(Context.Request.ServerVariables.Item("script_name"))

  但是,这不是我们的目的,我们最终目的是得到“Pictures”文件的完整路径。由于我们在创建Pictures文件夹时将其与Service1.asmx文件放在同一个文件下,所以我们只需将C:\inetpub\wwwroot\PictureService\Servcie1.asmx中Service1.asmx替换为Pictures就行了。

  代码段:

  Dim n As Integer

   For n = asmxPath.Length - 1 To n Step -1

    If asmxPath.Chars(n) = "\"c Then

     Dim serverPath As String = asmxPath.Substring(0, n)

     picturePath = serverPath & "\pictures"

     Exit For

    End If

   Next

   Return picturePath

  就是用来实现这个功能。

  上述两段代码运行之后,我们已经得到了期望的结果,即Pictures文件夹的完整路径为C:\inetpub\wwwroot\PictureService\Servcie1.asmx。

  现在,我们再回头看看代码的开始部分。在这个程序中我们引入了一个新的名称空间System.IO。我们将利用其类结口System.IO.DirectoryInfo获得文件夹的信息。下面这段代码中我们构建了一个新的属性PicttureFolder来返回PictureFolderPath指定文件夹的信息。

  Public ReadOnly Property PictureFolder() As DirectoryInfo

   Get

    Return New DirectoryInfo(PictureFolerPath)

   End Get

  End Property

  完成上述代码之后,我们已经获得了指定文件夹的相关信息。最后就是创建一个Web Service方法,来返回结果。

   Public Function GetPictureFolders() As String()

    Dim pictureFolder As DirectoryInfo = Me.PictureFolder

    Dim pictureSubFolders() As DirectoryInfo = pictureFolder.GetDirectories()

    Dim folderName(pictureSubFolders.Length - 1) As String

    Dim pictureSubFolder As DirectoryInfo, index As Integer

    For Each pictureSubFolder In pictureSubFolders

     folderName(index) = pictureSubFolder.Name

     index += 1

    Next

    Return folderName

  End Function

  通过对实例的分析,我们可以看出一个复杂的Web Service程序包含的内容极其广泛。本文只是着眼于Web Service程序表面的一些东西。其实质的技术点还有待读者自已去发掘。
                         原文

posted @ 2006-08-31 14:31  ㊣鑫哥  阅读(624)  评论(0编辑  收藏  举报