好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

WCF光芒下的Web Service

WCF光芒下的Web Service

学习 .NET 的开发人员,在 WCF 的光芒照耀下, Web Service  似乎快要被人遗忘了。因为身边做技术的人一开口就是 WCF 多么的牛逼!废话不多,本人很久不写博客,今天总结一下最近几日遇到的几个关于 WebService  跨语言的调用问题。

1  WebService  简介  

Web Service 也叫 XML Web Service WebService 是一种可以接收从 Internet 或者 Intranet 上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是 : 通过 SOAP 在 Web 上提供的软件服务,使用 WSDL 文件进行说明,并通过 UDDI 进行注册。

        Web Service 的简介就说这么多,大家都懂的,网上的资料太多了,搞过 Web Service 编程的人员都知道它的优点,没有搞过 WS 编程的人员也知道它的优点,这里不再累述。

          参考文章 :  http://baike.baidu.com/view/837392.htm

2  SOAP  消息结构  

    要学习 WebService  肯定要了解 Soap 协议,它是 WebService 的基础。

         SOAP ( Simple Object Access Protocol )简单对象访问协议,它是基于 XML 的消息传递协议,可以让软件组件和基于服务的应用程序能够使用标准的 HTTP 协议进行通信 (SOAP 是基于 HTTP 之上的 ) 。

         SOAP 的消息文档是一个 XML 格式的。相信大家都看到过:

  

  SOAP 主要是由 4 部分组成:

SOAP Envelope  

这是 XML 的顶层元素,语法如下:

( 1 )元素名为 Envelope ,必须存在,且为根元素。

( 2 )该元素可以包含命名空间和生命额外的属性。如果出现额外属性,则必须使用命名空间修饰。

( 3 )该元素可以包含额外的子元素,如果使用这些子元素,必须有命名空间修饰并且必须跟在 SOAP Body 元素之后,也就是说 Envelope 的直接子元素 Header 和 Body 必须排列在最前面。  

SOAP Header  

Header 应该是 Envelope 中的第一个子元素,为可选的,语法规则如下:

( 1 )元素名为 Header ,不是必须存在,但如果存在则必须是 SOAP Envelope 的第一个直接子元素。

( 2 ) Header 的所有直接子元素都是它的 Item ,每个 Itemdoiu 必须有命名空间修饰。

( 3 ) Header 的 Item 也可以包含下级子元素,但这些子元素不是 Header 的 Item ,而是具体 Item 的内容。

     此外, SOAP encodingStyle 属性用于指定 Header 条目的编码风格, mustUnderstand 属性和 actor 属性用于指定如何处理 Item 和由谁来处理。如:

<ENV:Header>

    <uniB2B:Priority MXLns:uniB2B="some-URI"

                     ENV:mustUnderstand="1">7</uniB2B:Priority>

</ENV:Header>

  SOAP Body

 SOAP Body 元素提供一个简单的用于消息的最终接收者交换信息的机制。其语法如下:

( 1 )元素名为 Body ,必须在 SOAP 消息中出现,同时必须是 SOAP Envelope 的直接子元素,若没有 Header ,则 Body 必须是第一个直接子元素;若有 Header ,则 Body 必须紧跟 Header 元素存在。

( 2 )与 Header 类似,每个 Body 的 Item 都必须由命名空间修饰。此外, Body 中有个 SOAP Fault 元素,用于指示调用错误信息。

( 3 ) Body 的 Item 下的子元素不是 Body 的 Item 了,而是 Item 的内容

SOAP Fault  

用于在 SOAP 消息中传输错误及状态信息。如果存在则必须是 Body 的一个 Item ,且 Body 中只能出现一次 Fault 。 SOAP Fault 元素有以下几个子元素:

(1) faultcode  必须在 SOAP Fault 元素中出现

(2)faultstring  该元素是为那些错误代码提供用户可以读懂的错误解释,它不是为程序处理而设置的。

(3)faultactor  该元素描述在消息路径中错误的引发者,它类似于 SOAP actor 属性,不过它不是指示 Header 条目的接收者,而是指示错误源。

(4)tail  该元素用于传输 Body 元素相关的应用程序的错误消息  

3   WebService 5 种模式

 请求响应模式

fire-and-forget 模式  

   高级消息模式 

           增量解析和处理模式 

           缓存模式 

4   WebService  自定义 SoapHeader 安全验证  

 SOAP  标头提供了一种方法,用于将数据传递到  XML Web services  方法或从  XML Web services  方法传递数据,条件是该数据不直接与  XML Web services  方法的主功能相关。例如,一个  XML Web services  可能包含若干个  XML Web services  方法,而每个方法都需要自定义的身份验证方案。您不用将参数添加到每个需要自定义身份验证方案的  XML Web services  方法,而可以将引用从  SoapHeader  派生的类的   SoapHeaderAttribute   应用于每个  XML Web services  方法。从  SoapHeader  派生的类的实现处理该自定义身份验证方案。按照此方式, XML Web services  方法使用  SOAP  标头来仅实现特定于它的功能并添加其他功能。

下面的列表概述接收和处理  SOAP  标头的基本步骤:

创建一个从  SoapHeader  派生的类,表示传入  SOAP  标头的数据。

将一个成员添加到实现  XML Web services  的类或  XML Web services  客户端代理类(它们属于在第一步创建的类型)。

指定第二步中在   MemberName   属性中创建的成员,将  SoapHeaderAttribute  应用于  XML Web services  方法或代理类中的对应方法。

在  XML Web services  方法或  XML Web services  客户端代码中访问  MemberName  属性,以处理在  SOAP  标头中发送的数据。

  验证例子代码:

  (1) 首先定义一个自定义 SoapHeader  

public   class  MyHeader:SoapHeader
    {
         public   int  ID {  get ;  set ; }

         public   string  Name {  get ;  set ; }

         public   string  PassWord {  get ;  set ; }

}

(2)  在 WebService 暴露的方法中添加 SoapHeader 描述

[WebService(Namespace =  " http://tempuri.org/ " )]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem( false )]
     public   class  Info : System.Web.Services.WebService
    {
         public  SoapUnknownHeader[] unknownHeaders;

         public  MyHeader MyHeader {  get ;  set ; }

        [WebMethod]
        [SoapHeader( " unknownHeaders " )]
         public   string  HelloWorld()
        {
            Console.WriteLine( " ?>>>>>>>>>>>>>>>>>>>> " );
             return   " Hello World " ;
        }


        [SoapHeader( " MyHeader " , Direction = SoapHeaderDirection.InOut)]
        [WebMethod]
         public   string  Audit()
        {
            Validate();

             return   " 这里是验证 " ;
        }

         // 验证函数 自定义
         private   string  Validate()
        {
             if  (MyHeader !=  null )
            {
                 if  (MyHeader.Name == MyHeader.PassWord)
                {
                     return   " 验证通过 " ;
                }
                 else
                {
                     return   " 验证失败 " ;
                }
            }
             return   " 未传递消息头 " ;
        }

这里重点看的是服务暴露出来的方法 public   string  Audit()  

在WebService中的类定义一个属性   public  MyHeader MyHeader {  get ;  set ; } 就是我们自定义的SOAPHeader,同时还要在Audit()方法上加上如下描述:

[SoapHeader( " MyHeader " , Direction = SoapHeaderDirection.InOut)] 

如果客户端传递了相应的SoapHeader就会使用此属性来接收消息,主要特性描述中的参数要指向定义的属性名。 

(3)客户端生存代理 

客户端生成代理大家都知道,工程--右键--添加Web引用即可,现在我们看看里面生成的代码 

MyHeader客户端生成的代理类  

 代理类中生存对应的属性,同时此类也是继承了SoapHeader类。

[System.Web.Services.Protocols.SoapHeaderAttribute( " MyHeaderValue " , Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute( " http://tempuri.org/Audit " , RequestNamespace= " http://tempuri.org/ " , ResponseNamespace= " http://tempuri.org/ " , Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public   string  Audit() {
             object [] results =  this .Invoke( " Audit " ,  new   object [ 0 ]);
             return  (( string )(results[ 0 ]));

public MyHeader MyHeaderValue {

      get {

                return this.myHeaderValueField;

      }

      set {

                this.myHeaderValueField = value;

      }

(4)客户端调用

MyService.Info info =  new  MyService.Info();
MyService.MyHeader myHeader =  new  MyService.MyHeader();
myHeader.ID =  1 ;
myHeader.Name =  " qingyuan " ;
myHeader.PassWord =  " qingyuan " ;
info.MyHeaderValue = myHeader;
string  content=  info.Audit();

Response.Write(content); 

5   异语言之间的调用  

在我们的工作中,很多时候遇到这样的问题,有人说 Java 不能调用 .NET  写 WebService 。对他们没有撒谎,那 WebService 跨平台岂不是笑话,其实不是这样的,这个时候我们真正应该研究的是 SOAP 的自己个组成部分,我们可以使用 WSDL 来查看他们的不同之处。  

  .NET 生存的 WSDL 一部分

 

  Java 生存的 WSDL 一部分

 

这里是同一个SoapHeader生成的WSDL,仔细看看还是有区别的,在java中的缺少一个form元素。 缺少这个元素就导致.NET的序列化机制无法识别这个xml文件。那该怎么办呢。

在.NET的自定义SoapHeader的属性上添加如下描述

 [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified)]

  6   .NET 中获取匿名 SoapHeader  内容

 很多时候,我们做事情就和孔雀开屏,当然这不是讽刺啊,题外话!我们喜欢强加一些自己的意愿和想法在里面。

          我存在一个 WebService 的服务端,现在客户端调用这个 WebService 的时候强制提交了一个 SOAPHeader 报文,希望 WebService 能够处理。上面一部分我们可以发现客户端提交一个 SOAPHeader 的时候服务端有一个承载体,因为我们在服务端的时候就在暴露的方法中用 SOAPHeader 描述过了,现在就是服务端没有使用自定义 SOAPHeader 描述,而客户端强制提交了一个 SOAPHeader ,这样我们怎么处理。

1 .   客户端定义一个 SOAPHeader 自定义对象

public   class  MyInfo:SoapHeader
{
         public  MyInfo()
        { 
        }

         public   int  ID {  get ;  set ; }

         public   string  Name {  get ;  set ; }

这里是在客户端添加的SoapHeader ,不要在服务端添加此类

     2 .   客户端代理方法添加 SOAPHeader 的描述  

/* ***************************************************************** */
         public  MyInfo MyInfo {  get ;  set ; }

        [SoapHeader( " MyInfo " , Direction = SoapHeaderDirection.InOut)]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute( " http://tempuri.org/HelloWorld " , RequestNamespace= " http://tempuri.org/ " , ResponseNamespace= " http://tempuri.org/ " , Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
         public   string  HelloWorld() {
             object [] results =  this .Invoke( " HelloWorld " ,  new   object [ 0 ]);
             return  (( string )(results[ 0 ]));
        }

  /* ***************************************************************** */

这里和普通的代理方式一样,添加客户端SOAPHeader的描述

3.   服务端添加匿名 SOAPHeader 的处理

public  SoapUnknownHeader[] unknownHeaders;

        [WebMethod]
        [SoapHeader( " unknownHeaders " )]
         public   string  HelloWorld()
        {
            Console.WriteLine( " ?>>>>>>>>>>>>>>>>>>>> " );
             return   " Hello World " ;
        }

   服务端需要使用SoapUnknownHeader来接收匿名提交的SoapHeader。因为在服务端没有对应的载体,而在暴露的方法上面也需要添加相应的描述 

     4.    客户端调用  

            MyService.Info info =  new  MyService.Info();
            MyInfo myInfo =  new  MyInfo();
            myInfo.ID =  1 ;
            myInfo.Name =  " dddd " ;
            info.MyInfo = myInfo;
             string  name = info.HelloWorld();

    Response.Write(name); 

  启动服务端的调试模式跟踪一下看看提交的数据

 从上图可以看出,数据已经传输过来了,得到的是一个xml格式的数据,对于xml的解析在.NET中不是难事,在此就可以完成匿名SoapHeader报文的发送和接收

7 JavaScript  异步调用 WebService 

 参考: http://www.cnblogs.com/qingyuan/archive/2009/12/09/1620405.html

  http://www.cnblogs.com/jeffreyzhao/archive/2007/07/23/something_about_calling_web_service_method.html

 

分类:  ASP.NET 杂文

标签:  WebService ,  SoapUnknownHeader ,  SoapHeader

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于WCF光芒下的Web Service的详细内容...

  阅读:63次