上一篇文章 "无侵入方面编程-用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. 学习Python遇到的那些坑

    1. 初始化一个类,这个方法名必须为”__init__(object)“.顺便提一下,两边的下划线是均是2个 2. 每个程序块都要使用冒号!!!! 3. 如果程序中使用了非英文字符,需要在Python ...

  2. VLOOKUP 函数

    如果需要在表格或区域中按行查找内容,可使用 VLOOKUP,它是一个查找和引用函数.例如,按部件号查找汽车部件的价格. =VLOOKUP(要查找的值.要在其中查找值的区域.区域中包含返回值的列号.精确 ...

  3. openstack(liberty): devstack之screen

    在devstack的stack.sh文件中,可以看到所有配置的service启动方式有两种,根据是否USE_SCREEN进行是在screen window中启动,还是直接起. 默认情况,USE_SCR ...

  4. Understanding and Managing SMTP Virtual Servers

    Simple Mail Transfer Protocol (SMTP) Service Overview The Simple Mail Transfer Protocol (SMTP) servi ...

  5. android学习笔记33——资源ShapeDrawable

    ShapeDrawable ShapeDrawable用于定义一个基本的几何图像(如,矩形.圆形.线条.......). 定义ShapeDrawable的XML文件的根元素是<shape.../ ...

  6. android学习笔记九——RatingBar

    RatingBar==>星级评分条 RatingBar和SeekBar十分相似,它们甚至有相同的父类:AbsSeekBar.两者都允许用户通过拖动来改变进度: 两者最大的区别在于RatingBa ...

  7. 深入分析Volatile的实现原理(转)

    引言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”.可见性的意思是当 ...

  8. ScalaTour 2.函数

    /** * 1. case class与模式匹配 */ object TestFunction extends App{ def value(expr:Expr): Int = expr match ...

  9. (WPF, MVVM) Textbox Binding

    参考:http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.110).aspx Te ...

  10. 在C#中子线程如何操作主线程中窗体上控件

    在C#中,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能 简单的通过控件对象名来操作,但不是说不能进行操作,微软 ...