博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对SOAP消息头的处理
阅读量:4028 次
发布时间:2019-05-24

本文共 7341 字,大约阅读时间需要 24 分钟。

第二部分 对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/

转载地址:http://cmmbi.baihongyu.com/

你可能感兴趣的文章
第一性原理:戳中问题本质的人是怎么思考的?
查看>>
No.147 - LeetCode1108
查看>>
No.148 - LeetCode771
查看>>
No.174 - LeetCode1305 - 合并两个搜索树
查看>>
No.175 - LeetCode1306
查看>>
No.176 - LeetCode1309
查看>>
FE:http状态码
查看>>
No.182 - LeetCode1325 - C指针的魅力
查看>>
mac:移动python包路径
查看>>
mysql:sql create database新建utf8mb4 数据库
查看>>
mysql:sql alter database修改数据库字符集
查看>>
mysql:sql alter table 修改列属性的字符集
查看>>
mysql:sql drop table (删除表)
查看>>
mysql:sql truncate (清除表数据)
查看>>
scrapy:xpath string(.)非常注意问题
查看>>
yuv to rgb 转换失败呀。天呀。谁来帮帮我呀。
查看>>
yuv420 format
查看>>
单纯的把Y通道提取出来能正确显示出灰度图来为什么我的Qt就显示不出来呢转换有问题呀?
查看>>
YUV420只绘制Y通道
查看>>
yuv420 还原为RGB图像
查看>>