上一篇文章 "无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)"中,我们实现了监视每个页面的执行情况和调用WebService的简单信息。

这次我们继续深入一下SoapExtension的应用,在不改变Soap的WSDL文档的情况下,配合在Dotnet编写的WebService站点配置我们编写的SoapExtension,来穿透传输我们自定义的数据对象。由于SoapExtension是全局的,我们还要加一些标识来区分服务器是否已经配置了我们的SoapExtension,从而不影响其它的WebService调用。

在SoapExtension中,我想到有两种方案:
    一种是直接在SoapMessage.Headers中插入自定义的SoapHeader对象,然后在客户端的序列化后,从SoapUnknownHeader中取出数据,然后反序列化成自定义的对象。
    第二种是对SoapMessage.ContentType 添加一个额外的标识,在另一方检测这个标识,来从流中取出自己长度的数据。反序列化成自定义的对象。

我感觉第二种方案比较简单,高效,我们看一下代码:

    /// <summary>
    /// WSInvokeMonitorExtension 的摘要说明。
    /// </summary>
    public class StreamWSInvokeMonitorExtension : SoapExtension
    {
        private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
        private const int MaxDataLength = 5 * 1024 * 1024;  //5M
        private XmlSerializer serializer = new XmlSerializer(typeof(DbConnInfo));
        private Stream originStream;
        private Stream usingStream = new MemoryStream();
        private WSInvokeInfo invokeInfo = new WSInvokeInfo();
        public override System.IO.Stream ChainStream(System.IO.Stream stream)
        {
            originStream = stream;
            return usingStream;
        }         public override object GetInitializer(Type serviceType)
        {
            return null;
        }         public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return null;
        }         public override void Initialize(object initializer)
        {         }         public override void ProcessMessage(SoapMessage message)
        {
            if(message is SoapClientMessage)
            {
                switch (message.Stage) 
                {
                    case SoapMessageStage.BeforeSerialize:
                        this.invokeInfo.BeginInvokeTime = DateTime.Now;
                        this.invokeInfo.MethodName = message.MethodInfo.Name;
                        break;                     case SoapMessageStage.AfterSerialize:
                        usingStream.Seek(0, SeekOrigin.Begin);
                        CopyStream(usingStream, originStream);
                        break;                     case SoapMessageStage.BeforeDeserialize:
                        usingStream.SetLength(0);
                        CopyStream(originStream, usingStream);
                        usingStream.Seek(0, SeekOrigin.Begin);
                        if(message.ContentType.IndexOf("ExtInfo=true") != -1){
                            //先读出自己的信息
                            byte[] bytesFlags = new byte[]{66,69}; // BE  标识                             if(usingStream.ReadByte() == bytesFlags[0])  //检验标志位
                            {
                                byte[] bytesLength = new byte[BitConverter.GetBytes((Int32)0).Length];  
                                usingStream.Read(bytesLength,0, bytesLength.Length); //读取长度
                                int length = BitConverter.ToInt32(bytesLength,0);                                 if(length < MaxDataLength)   //检验数据是否非法
                                {
                                    if(usingStream.ReadByte() == bytesFlags[1])   //检验标志位
                                    {
                                        byte[] bytesData = new byte[length];
                                        usingStream.Read(bytesData,0, bytesData.Length);
                                        using(MemoryStream ms = new MemoryStream(bytesData))
                                        {
                                            DbConnInfo header = serializer.Deserialize(ms) as DbConnInfo;
                                            Debug.WriteLine(header.Info);
                                        }                                         break;
                                    }                                 }                             }                             //数据不对,则重置流位置
                            usingStream.Position = 0;
                        }                         break;                         // About to call methods
                    case SoapMessageStage.AfterDeserialize:
                        //添加到Module记录
                        this.invokeInfo.EndInvokeTime = DateTime.Now;
                        PageInfo pageInfo = (PageInfo)HttpContext.Current.Items[WSInvokeMonitorKey] ;
                        if(pageInfo != null)
                        {
                            pageInfo.AppendInvokeInfo(this.invokeInfo);
                        }                         break;                         // After Method call                     default:
                        throw new Exception("No stage such as this");
                }             }
            else if(message is SoapServerMessage)
            {
                switch (message.Stage) 
                {
                        // Incoming from client
                    case SoapMessageStage.BeforeDeserialize:
                        usingStream.SetLength(0);
                        CopyStream(originStream, usingStream);
                        usingStream.Seek(0, SeekOrigin.Begin);                         break;                         // About to call methods
                    case SoapMessageStage.AfterDeserialize:
                        break;                         // After Method call
                    case SoapMessageStage.BeforeSerialize:
                        
                        //设置自定义Header
                        usingStream.SetLength(0);  //清空并先写入自定义的信息
                                                 byte[] bytesData = null;
                        using(MemoryStream ms = new MemoryStream())
                        {
                            serializer.Serialize(ms,new DbConnInfo("3个数据库连接"));  //服务端自定义的信息
                            bytesData = ms.ToArray();
                        }
                        message.ContentType += ";ExtInfo=true";
                        //写入标识
                        byte[] bytesFlags = new byte[]{66,69}; // BE
                        usingStream.WriteByte(bytesFlags[0]);                         //写入长度
                        byte[] dataLength = BitConverter.GetBytes(bytesData.Length);
                        usingStream.Write(dataLength, 0, dataLength.Length);                         //再写入标志
                        usingStream.WriteByte(bytesFlags[1]);                         //写入数据
                        usingStream.Write(bytesData, 0, bytesData.Length);
                        
                        break;                         // Outgoing to other 
                    case SoapMessageStage.AfterSerialize:
                        usingStream.Seek(0, SeekOrigin.Begin);
                        CopyStream(usingStream, originStream);
                        break;                     default:
                        throw new Exception("No stage such as this");
                }             }
        }         private void CopyStream(Stream src, Stream des)
        {
            byte[] buf = new byte[1024];
            int length = 0;
            do 
            {
                length = src.Read(buf,0,buf.Length);
                des.Write(buf,0,length);
            } while (length == buf.Length);                   }
    }     [System.Serializable]
    public class DbConnInfo 
    {
        private string info;
        public string Info
        {
            get { return info; }
            set { info = value; }
        }         public DbConnInfo()
        {
        }         public DbConnInfo(string info)
        {
            this.Info = info;
        }
        
    }

代码中,在服务端写入标识: message.ContentType += ";ExtInfo=true";

然后在客户端检测:if(message.ContentType.IndexOf("ExtInfo=true") != -1){...}
   这样便保证了不会影响其它没有加载Soap扩展的调用。

到目前为至,我们已经成功的把服务端的信息对象,在不改变WSDL的情况下,无侵入的传递到调用端。具体收集什么信息,就要在WebService端进行收集了!我这里的要求是收集数据库连接的情况,下一次继续介绍吧。

附:方案一实现代码:

 
    [System.Serializable]
    public class DbConnInfoSoapHeader 
    {
        private string info;
        public string Info
        {
            get { return info; }
            set { info = value; }
        }         public DbConnInfoSoapHeader()
        {         }         public DbConnInfoSoapHeader(string info)
        {
            this.Info = info;
        }
        
    }     [System.Serializable]
    public class SoapHeaderWrap : SoapHeader
    {
        private byte[] soapData = null;
        private object data;         [XmlIgnoreAttribute]
        [SoapIgnoreAttribute]
        public object Data
        {
            get { return data; }
            set 
            {
                data = value;
                soapData = null;
            }
        }
        private string key;
        [XmlAttribute]
        public string Key
        {
            get { return key; }
            set { key = value; }
        }         [XmlAttribute]
        public string TypeName 
        {
            get{                 return this.Data.GetType().AssemblyQualifiedName;
            }
            set{}
        }         public byte[] SoapData
        {
            get
            {
                if(soapData == null && this.Data != null)
                {
                    using(MemoryStream ms = new MemoryStream())
                    using(StreamWriter sw = new StreamWriter(ms,new UTF8Encoding(false)))
                    {
                        XmlSerializer serializer = new XmlSerializer(this.Data.GetType());
                        serializer.Serialize(sw, this.Data);
                        ms.Position = 0;
                        soapData = ms.ToArray();
                    }                 }                 return soapData;
            }
            set {             }
        }         public SoapHeaderWrap(string key, object soapData)
        {
            this.Key = key;
            this.Data = soapData;
        }         public SoapHeaderWrap(string key)
            :this(key,null)
        {
        }         public SoapHeaderWrap()
            :this(string.Empty)
        {
        
        }     }

http://www.cnblogs.com/evlon/archive/2009/06/01/1493923.html

无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(二)的更多相关文章

  1. 无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)

    先简单介绍一下项目吧,我们这个项目是用VS2003开发的,老早一个项目.WEB前端机+业务处理(WebService层)+数据库分别布置在不同的计算机上. 现在老总有一个需求,要统计出每个页面的执行时 ...

  2. Android平台免Root无侵入AOP框架Dexposed使用详解

    Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...

  3. Android免Root无侵入AOP框架Dexposed

    Dexposed框架是阿里巴巴无线事业部近期开源的一款在Android平台下的免Root无侵入运行期AOP框架,该框架基于AOP思想,支持经典的AOP使用场景,可应用于日志记录,性能统计,安全控制,事 ...

  4. Dexposed:android免Root无侵入Aop框架

    在网上看到了阿里推出的一个android开源项目,名为Dexposed, 是一个Android平台下的无侵入运行期AOP框架.旨在解决像性能监控.在线热补丁等移动开发常见难题,典型使用场景为: AOP ...

  5. 无插件Vim编程技巧

    无插件Vim编程技巧 http://bbs.byr.cn/#!article/buptAUTA/59钻风 2014-03-24 09:43:46 发表于:vim  相信大家看过<简明Vim教程& ...

  6. 单点登录CAS使用记(八):使用maven的overlay实现无侵入的改造CAS

    前期在学习CAS部署的过程中,都是网上各种教程,各种方案不停的尝试. 期间各种侵入改源码,时间久了,改了哪个文件,改了哪段配置,增加了哪段代码,都有可能混淆不清了. 而且最大的问题是,万一换个人来维护 ...

  7. 发布时去掉 debug 和 提醒日志,简单无侵入

    在 proguard 文件中加入下面代码,让发布时去掉 debug 和 提醒日志,简单无侵入! -assumenosideeffects class android.util.Log { public ...

  8. 无插件VIM编程技巧(网摘)

    无插件VIM编程技巧 原文出处:[陈皓 coolshell] 相信大家看过<简明Vim教程>也玩了<Vim大冒险>的游戏了,相信大家对Vim都有一个好的入门了.我在这里把我日常 ...

  9. Hook 无侵入式埋点(页面统计)

    一.技术原理 Method-Swizzling 黑魔法 方法交换(不懂的可以查) 二.页面统计 某盟页面统计SDK需要开发者在APP基类里实现ViewDidAppear和viewDidDisappea ...

随机推荐

  1. linux包之bash之内置命令ulimit

    概述 [root@localhost ~]# rpm -qa|grep bashbash-4.1.2-15.el6_4.x86_64 linux limits.conf 配置 limits.conf ...

  2. java 实现mysql数据库导出

    package com.zbb.util; import java.io.BufferedReader;import java.io.File;import java.io.FileInputStre ...

  3. having 子句与where区别

    having 子句,条件子句 与 where 功能.用法相同,执行时机不同. where 在开始时执行检测数据,对原数据进行过滤. having 对筛选出的结果再次进行过滤. having 字段必须是 ...

  4. 本地计算机上的OracleOraDb11g_home1TNSListener服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止。——Oracle监听器服务无法启动!

    问题: oracle服务设置为手动启动.但是开机后手动启动监听服务后弹出框,提示“本地计算机上的OracleOraDb11g_home1TNSListener服务启动后停止.某些服务在未由其他服务或程 ...

  5. eclipse解压后启动弹出A Java Runtime Evironment(JRE) or Java Development Kit(JDK)....

    系统环境:win7 64bit JDK:jdk-7u79-windows-x64 Eclipse:eclipse-jee-helios-win32 启动eclipse:弹出A Java Runtime ...

  6. CK方程

    上文中,“到时间n为止进入任意一个特定的状态集合”应理解为“在时间n及之前进入的都算”. 只要进入了该状态集合,之后是否离开已经不重要了.这个可类比于“先赢若干局”的赌徒问题:即使在赢得若干局后继续赌 ...

  7. Python builtins

    >>> dir (__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseExcepti ...

  8. IIS SMTP status codes

    Here are the meaning of SMTP status codes. Status Code Description 211 System status, or system help ...

  9. CPU GPU天梯图

    2014年2月

  10. 获得Unix/Linux系统中的IP、MAC地址等信息

    获得Unix/Linux系统中的IP.MAC地址等信息 中高级  |  2010-07-13 16:03  |  分类:①C语言. Unix/Linux. 网络编程 ②手册  |  4,471 次阅读 ...