`
school104
  • 浏览: 71398 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

对SOAP消息头的处理

 
阅读更多
第二部分  对SOAP消息头的处理

SOAP消息头通常包含与消息体或SOAP处理(应用)方式相关的信息,比如消息路径、数字签名、认证信息,消息关联性信息、消息体的加密公匙等等。同第一部分一样我们可以利用属性机制来获取控制SOAP消息头的句柄,对SOAP消息头进行自定义,然后将头数据传递到Web services 方法或从Web services方法返回头数据。消息头数据是不直接与Web services 方法的主功能相关的,因为它不是Web services方法的参数。

1.服务提供端的工作

我将以一个简单的认证服务作为例子,来讲解如何在程序中定义和使用自定义的消息头。首先我们所需要做的事情,就是在Web Service端从抽象类SoapHeader继承一个类(假设类名为AuthenticationHeader),用来表示SOAP消息头内的数据,注意这个类的类名将是SOAP消息头下的根元素(SOAP消息头的子元素)的名字(<soap:Header><AuthenticationHeader>…</AuthenticationHeader></soap:Header>),而类的公共成员变量名或属性名(假设一个属性名为AuthenticationToken)将是其下的子元素的名字(<soap:Header><AuthenticationHeader><AuthenticationToken>。。。</AuthenticationToken></AuthenticationHeader></soap:Header>)。对于客户端所发送的请求消息的消息头就需要遵守这个格式,向Web Service方法提供需要的信息。当Web Service方法接收到SOAP消息后,会进行并行化操作,根据定义新建一个SOAP头类对象,然后将SOAP消息头内的数据赋给该对象的相应属性,以便Web Service方法直接利用。以下就是该认证消息头类的主要代码:

     public class AuthenticationHeader : SoapHeader

     {  

         private string _AuthenticationToken = String.Empty;

         //该属性允许Web Service设置和获取SOAP Header的AuthenticationToken元素的值

         public string AuthenticationToken

         {

              get {    return _AuthenticationToken;     }

              set {    //验证接收到的AuthenticationToken元素的值,如果为空则抛出异常

                       if (value == String.Empty)

                       {

                            throw new SoapException("No Authentication Token Received",null);

                       }

_AuthenticationToken = value;  

}

         }

     }

一旦定义好了消息头的格式,下一步的工作就是将SOAP消息头的数据与Web method关联起来。SoapHeader属性就是用来做这项工作的。首先需要向提供服务的WebService类添加一个公共成员变量(本例中为AuthHeader),这个变量的类型就是上面从SoapHeader类继承的那个类AuthenticationHeader。这里又引入了一个属性SoapHeader,这个SoapHeader实际上就是SoapHeaderAttribute,SoapHeaderAttribute类的构造函数将头类变量的名字作为参数,并且加在了一个WebMethod的前面,这是为了将该SOAP头类与指定的Web Service方法关联起来,作为该WebMethod的一部分。下面是服务端WebService类的主要代码:

    public class SoapHeaderDemo : System.Web.Services.WebService

     {

         public AuthenticationHeader AuthHeader;

         // public ReceiptorHeader ReceiptHeader = new ReceiptorHeader();

         …

         //SOAP header将确保每个用户都与一个Authenticationtoken相关联

         [WebMethod]

         [SoapHeader("AuthHeader", Direction=SoapHeaderDirection.In, Required=true)]

         // [SoapHeader("ReceiptHeader", Direction=SoapHeaderDirection.Out, Required=true)]

         public Account GetAccountDetails(int accountID)

         {

              //将认证标记传到Account的构造函数中,以便查询该标记对应的UserID。由于前面引入了// SoapHeader属性,这里就可以直接使用头类对象了

              Account ad = new Account(accountID,AuthHeader.AuthenticationToken);

              //如果UserID和AccountID都匹配,则说明认证成功,返回一个Account对象

              return ad;

         }

     }



请注意,这里没有创建SOAP头类对象AuthHeader的实例,因为AuthHeader处理的是来自客户端的SOAP消息头。由于SoapHeader属性的属性项Direction =  SoapHeaderDirection.In,ASP.NET运行时会在接收到来自客户端的消息后自动创建AuthHeader的实例,并用SOAP消息头内的数据对其相应属性赋值。如果WebService方法要向客户端发送SOAP消息头(假设根元素为ReceiptorHeader),则必须对该头类对象(假设SOAP头类对象为ReceiptHeader)实例化,且服务端对应的SoapHeader属性的属性项Direction=SoapHeaderDirection.Out

SOAP属性里有两个属性项Direction和Required。Direction说明SOAP消息是从客户端发送到服务端(In)还是刚好相反(Out),或是两者都有(InOut)。 Required则指明消息头是否必须被包括在SOAP消息中。如果指定为True而没有包括,ASP.NET会抛出异常(SoapException,后面会讲到)。Required默认值为True,此时ASP.NET不支持HTTP GET/POST 绑定,也就是说不能通过ASP.NET自动生成的测试页来访问这个Web Method了。注意,“必须包含”并不表示“必须处理”,事实上完全有可能你向服务端发送了要求包含的SOAP消息头数据,而Web Service却并没有做任何处理(你会不会感觉有点“浪费表情”^_^),但这不会抛出任何异常。

另外,Required与Web service接口紧密相关,对这个属性的改变会影响到该Web service的WSDL。如果Required设置为True,则在SOAP 绑定扩展性元素中定义的header元素的required属性也被设为true,同时在WSDL里会出现对消息头元素的Schema定义,客户端的SOAP消息头格式必须符合这个定义,否则服务端会抛出异常。

现在客户端传过来的SOAP消息头内的数据与Web Method已经关联起来了,并可直接通过头类对象访问,其余的工作就是完善验证和数据处理功能的代码,这里就不再熬述了。

2.客户端的工作

上面提到的是服务端的处理,那客户端如何在调用Web Method时将消息头加进去呢?方法就是通过客户端代理类创建WebService端消息头类(本例为AuthenticationHeader)对象的实例,将需要发送的数据赋到相应的公共成员变量里去,再调用Web Method就行了。下面给出一个在请求消息中添加信息头的例子:



//从本地取得用户的认证标记

_authToken = (string)this.ViewState["AuthToken"];

//生成代理类对象

SoapHeaderClient.localhost.SoapHeaderDemo demo =

                   new SoapHeaderClient.localhost.SoapHeaderDemo();

//生成代理头类对象

demo.AuthenticationHeaderValue  =

                   new SoapHeaderClient.localhost.AuthenticationHeader();

//将认证标记添加到代理头类对象的相应元素中

demo.AuthenticationHeaderValue.AuthenticationToken = _authToken;



3.SOAP Header的属性

但是这里还有个问题,客户端向服务端发送的SOAP消息头除了Web Method能够处理的以外,可能还包括了一些Web Method不能识别(更不能处理)的SOAP消息头。更可怕的是客户端甚至可能将这些服务端不能识别的SOAP消息头所对应的SOAP头类对象的MustUnderstand属性设置为true,这样可就麻烦了。呵呵,幸运的是.NET还提供了一种机制专门解决这种不明SOAP消息头的处理问题。首先我们还是来了解一下MustUnderstand属性吧。

MustUnderstand属性来自于SoapHeader类,它与前面讲到的SoapHeaderAttribute类的Required属性完全不同,它表示消息的接收者是否必须理解(处理)这个指定的消息头。

DidUnderstand也是SoapHeader类的一个属性,在Web method中可以通过设置某个头类对象的DidUnderstand属性的值,来告诉客户端哪些信息头已经被处理,哪些没有处理。对于由Web method定义的消息头,DidUnderstand的默认值为true。需要指出的是,对于客户端mustUnderstand属性设置为True而在Web method中却没有处理的消息头,要么将DidUnderstand属性的值设为False,要么就主动抛出一个异常,否则就会出错!在Web Method返回前,.NET会检查所有客户端传过来的SoapHeader,一旦发现客户端将mustUnderstand属性设置为True,而对应的DidUnderstand属性却为False,就会抛出SoapHeaderException异常。

针对上面SOAP消息头可能没有处理的情况,可以在Web method的开始部分将所有SoapHeader的DidUnderstand属性设置为False,一旦某个SoapHeader被处理了,就将其DidUnderstand设置为True。或者在Web method决定是否对某个SoapHeader进行处理时,将客户端设置的MustUnderstand属性的值作为一个判断条件。

4.不明SOAP消息头的处理

.NET提供了一种机制来处理没有被Web method正式定义的Soap Header(SoapUnknownHeader)。SoapUnknownHeader类继承自SoapHeader,因此也有 MustUnderstand和DidUnderstand属性。SoapUnknownHeader类型的对象是松散的,它自己定义的属性只有Element(XmlElement类型),Element属性用来访问不明Soap头类的根元素,可以通过它来遍历该头类的所有元素的内容。

和其它SoapHeader类一样,可以通过SoapHeader属性将SoapUnknownHeader与Web method关联起来。如果有不只一个SoapUnknownHeader,SoapHeader属性的MemberName属性项就是一个数组。下面是一个处理不明SOAP消息头例子:

public class MyWebService

{

     public MyHeader myHeader;

     // 声明数组准备接收所有的不明SOAP消息头

     public SoapUnknownHeader[] unknownHeaders;



     [WebMethod]

     [SoapHeader ("myHeader", Direction=SoapHeaderDirection.InOut,Required=true)]

     //通过SoapHeader属性,接受所有不明SOAP消息头

     [SoapHeader ("unknownHeaders", Required=false)]



     public string MyWebMethod()

     {

         string unknownHeaderAttributes = String.Empty;

         // 处理已知消息头myHeader,过程略

         // 检查每个不明SOAP消息头

         foreach (SoapUnknownHeader header in unknownHeaders)

         {

              // 列出每个不明SOAP消息头的根元素的每个属性名值对

              foreach (XmlAttribute attribute in header.Element.Attributes)

              {

                   unknownHeaderAttributes = unknownHeaderAttributes + attribute.Name + ":" +                    attribute.Value + ";";

              }

              // 告诉客户端,这些不明SOAP消息头不能够处理

              header.DidUnderstand = false;

         }

         return unknownHeaderAttributes;

     }

}

对于这个例子,如果客户端要求必须对某个不明SOAP消息头进行处理,在Web Method返回时会自动抛出异常(或主动抛出异常,详细描述),客户端可以根据异常原因来决定进一步的操作。

5.SOAP异常

当客户端使用SOAP进行调用时,由于各种各样的原因Web Services方法可能会引发SoapException(继承自Exception类),比如名称空间不匹配、SOAP头未处理(此时引发SoapHeaderException)、编码格式不被识别、数据库处理错误、主动抛出异常等等。异常在服务器上被捕获并包装在一个新的SoapException实例内,然后写入SOAP体(Body)的Fault元素中,作为响应返回给客户端。下面是一个返回异常的SOAP消息体:

<soap:Body>

<soap:Fault>

<faultcode>soap:Server</faultcode> --错误码

<faultstring>System.Web.Services.Protocols.SoapHeaderException: 服务器在消息中未找到所需的 AuthenticationHeader SOAP 标头。

   at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)

   at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()

   at System.Web.Services.Protocols.WebServiceHandler.Invoke()

   at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

</faultstring> --错误内容

<detail />     --在抛出异常时自定义的详细错误信息,这里为空

</soap:Fault>

</soap:Body>



前面说过.NET会自动根据错误原因和类型生成相应的异常,同时Web Services也可以根据需要人工抛出异常,不管是SoapException,还是普通的Exception,例如:

SoapException se = new SoapException("Fault occurred", SoapException.ClientFaultCode,Context.Request.Url.AbsoluteUri,node);

throw se;



throw new Exception("Fault occurred");

而客户端可以通过下面的方法来获取关于异常的详细信息:

try

{ … }

catch (Exception e)

{

Console.WriteLine(e.Source);

Console.WriteLine(e.Message);

//SoapException的属性

Console.WriteLine(e.Code);

Console.WriteLine(e.Actor);

Console.WriteLine(e.Detail);

}

http://clockzxj.blog.163.com/blog/static/18950624200711441727132/
分享到:
评论
1 楼 Dwayne_Lt 2016-02-24  
第一部分呗?

相关推荐

    gsoap 2.8 (SOAP/XML 关于C/C++ 语言的自动化实现工具内附 CSharp webservice例子,及GSOAP client和server例子)

     ×可定制的SOAP消息头处理机制,可以用来保持状态信息  2 gSoap2.2版与gSOAP 2.1版(或以前版本)的不同  如果你是从2.1版升级到2.2或以后版本,请注意这些变化。  为了能够分离传输、内容编码、映射中的接收/...

    axis-bin-1_4.zip

    初步支持带附件的SOAP消息。 在EJB方面提供把EJB作为Web服务的访问途经。 基于Servlet的HTTP传输。 基于JMS的传输。 独立的服务器(但需要HTTP 服务器和Servlet容器支持)。 提供客户端、服务器端相关应用程序的样例...

    JAVA.WEB服务.构建与运行

     · 认识SOAP消息的结构  · 学习如何交付基于Java的RESTful Web服务和消耗商业RESTful服务  · 了解对基于SOAP和基于REST的Web服务的安全要求  · 学习如何在各种环境下部署JAX-WS服务  不管是学生还是有经验...

    超级有影响力霸气的Java面试题大全文档

     多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 5、String是最基本的数据类型...

    ASP.NET的网页代码模型及生命周期

    Cookie在客户端用户保存网站的少量的用户信息,服务器可以通过编程的方法获取用户信息,Cookie信息和页面请求通常一起发送到服务器,服务器对客户端传递过来的Cookie信息做处理。通常Cookie保存用户的登录状态、...

    java开源包1

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包11

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包2

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包3

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包6

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包5

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包10

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包4

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包8

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包7

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    java开源包9

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    JAVA上百实例源码以及开源项目

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    java开源包101

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    Java资源包01

    多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写...

    JAVA上百实例源码以及开源项目源代码

    Message-Driven Bean EJB实例源代码 2个目标文件 摘要:Java源码,初学实例,EJB实例 Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式 //给客户发一个感谢...

Global site tag (gtag.js) - Google Analytics