• 无侵入方面编程用HttpModule+SoapExtension监视页面执行参数(二)


        上一篇文章 "无侵入方面编程-用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端进行收集了!我这里的要求是收集数据库连接的情况,下一次继续介绍吧。

       附:方案一实现代码:


     

    方案一代码

     

  • 相关阅读:
    Maven
    Maven
    Tomcat8
    首先,定义一个时钟类——Clock,它包括三个int型 成员变量分别表示时、分、秒,一个构造方法用于对三个成员变量(时、分、秒) 进行初始化,还有一个成员方法show()用于显示时钟对象的时间。其次,再定义 一个主类——TestClass,在主类的main方法中创建多个时钟类的对象,使用这 些对象调用方法show()来显示时钟的时间。
    首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”、“取款”和“余额查询”。其次, 编写一个主类,在主类中测试Account类的功能。
    .编写一个Java应用程序,该程序中有3个类:Lader、Circle和主类A。具体要求如下:Lader类具有类型为double的上底、下底、高、面积属性,具有返回面积的功能,包括一个构造方法对上底、下底、高进行初始化。Circle类具有类型为double的半径、周长和面积属性,具有返回周长、面积的功能,包括一个构造方法对半径进行初始化。主类A用来测试类Lader和类Circle的功能
    输入三个整数x,y,z,请把这三个数由小到大输出。
    有1、2、3、4四个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
    (1)编写西游记人物类(XiYouJiRenWu) 其中属性有:身高(height),名字(name),武器(weapon) 方法有:显示名字(printName),显示武器(printWeapon) (2)在主类的main方法中创建二个对象:zhuBaJie,sunWuKong。并分别为他 们的两个属性(name,weapon)赋值,最后分别调用printName, printWeapon方法
    输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
  • 原文地址:https://www.cnblogs.com/evlon/p/1493923.html
Copyright © 2020-2023  润新知