SOAP Extension(SOAP扩展)可以封装可重用的功能。比如上一篇讲的通过Soap Header进行服务的访问控制。这篇随笔里我们要利用SOAP扩展做一下对利用Soap Header校验用户身份的封装和解决网友提出的明文传输身份信息不安全的问题。
      首先,介绍一下几个相关的类。System.Web.Services.Protocols名称空间下SoapExtension,SoapExtensionAttribute是两个抽象类,不能够实例化,我们要做的事情就是分别继承这两个抽象类,实现自定义类。SoapExtensionAttribute又继承自System.Attribute,说明它是一个Attribute(这个东西不太好翻译,有人译成属性之类,我考虑了一下,感觉翻译成标签更形象,为什么呢?我们用这种类时,一般会在类或方法等上方加[Attribute],这就有点像给东西贴一个标签,告诉别人这个有什么特征,作什么用途)。
      我们开始实现自定义的SoapExtension和SoapExtensionAttribute,下边是具体代码,代码中用到了对称加密,我封装了一下MSDN里的提供的一个实现,可以下载源文件在这里/Files/DavidFan/Encryptor.rar。需要引用的名称空间,其中包括我封装的加密类所在的名称空间
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Services.Protocols;
using David.Fan.Encrypt;
      下边是自定义的MyExtensionAttribute类,[AttributeUsage(AttributeTargets.Method)]中AttributeTargets.Method是只可以对方法应用,当然你还可以根据Soap扩展的不同功能,设置其它的应用类型。
[AttributeUsage(AttributeTargets.Method)]
public class MyExtensionAttribute : SoapExtensionAttribute
{
    
int _priority = 1;

    
public override int Priority
    
{
        
get return _priority; }
        
set { _priority = value; }
    }


    
public override Type ExtensionType
    
{
        
get return typeof(MyExtension); }
    }

}
      接下来是MyExtension类,继承自SoapExtension
public class MyExtension : SoapExtension
{
    
//这个override的方法会被调用四次
    
//分别是SoapMessageStage的BeforeSerialize,AfterSerialize,BeforeDeserialize,AfterDeserialize
    public override void ProcessMessage(SoapMessage message)
    
{
        
if (message.Stage == SoapMessageStage.AfterDeserialize)//反序列化之后处理
        {
            
bool check = false;
            
foreach (SoapHeader header in message.Headers)
            
{
                
if (header is MySoapHeader)
                
{
                    MySoapHeader myHeader 
= (MySoapHeader)header;
                    
//解密
                    myHeader.Name = Security.Decrypt(myHeader.Name);
                    myHeader.PassWord 
= Security.Decrypt(myHeader.PassWord);

                    
if (myHeader.Name == "admin" || myHeader.PassWord == "admin")
                    
{
                        check 
= true;
                        
break;
                    }

                }

            }

            
if (!check)
                
throw new SoapHeaderException("认证失败", SoapException.ClientFaultCode);
        }

    }

    
public override Object GetInitializer(Type type)
    
{
        
return GetType();
    }

    
public override Object GetInitializer(LogicalMethodInfo info, SoapExtensionAttribute attribute)
    
{
        
return null;
    }

    
public override void Initialize(Object initializer)
    
{
    }

}
      最后一步如何应用Soap扩展。很简单只需[MyExtensionAttribute]即可。这里用到了SoapHeader,如果你对它不是很熟悉的话,可以参考我的上一篇随笔。
public class MySoapHeader : SoapHeader
{
    
string _name;
    
string _passWord;

    
public string Name
    
{
        
get return _name; }
        
set { _name = value; }
    }

    
public string PassWord
    
{
        
get return _passWord; }
        
set { _passWord = value; }
    }

}

[WebService(Namespace = "http://DavidFan.cnblogs.com")]
public class MyService : System.Web.Services.WebService
{
    
public MySoapHeader header;

    [MyExtensionAttribute]
    [SoapHeader(
"header", Direction = SoapHeaderDirection.In)]
    
public string CheckHeader()
    
{
        
//业务逻辑.
        return "Something done";
    }

}

      CheckHeader方法的实现你可以和我上一篇的MyService的CheckHeader方法作一下对比。就看出来Soap扩展的一点好处了。客户端将身份信息加密传送。服务器端拿到加密串进行解密,然后校验,不匹配则摆出异常。
      这里只是对Soap扩展使用的一个特别的简单的举例,当然你还可以发挥,比如压缩消息,日志记录,Trace之类,网上也有很多文章讲。谢谢大家!