先简单介绍一下项目吧,我们这个项目是用VS2003开发的,老早一个项目。WEB前端机+业务处理(WebService层)+数据库分别布置在不同的计算机上。

现在老总有一个需求,要统计出每个页面的执行时间,以及每次调用过哪些WebService方法,调用的时间等参数。

可行的方案有好多,但我感觉使用HttpModule+SoapExtension,可以不在改变目标系统源码的基础上,完成这项工作。也许有一天,老总说,现在不需要再统计了,我就直接配置一下,不再统计就行了。

由于要调用WebService,我们采用编写一个SoapExtension,在它的ProcessMessage函数中,在message.Stage是 BeforeSerialize 时,记一个开始时间,并采集一些数据,在message.Stage==AfterDeserialize时,再采集一些时间等数据。最后通过HttpContext.Current.Items[WSInvokeMonitorKey]获取HttpModule的对象,把采集到的数据放在HttpModule里面。

在HttpModule层,我们可以context的BeginRequest、PreRequestHandlerExecute、PreSendRequestContent、EndRequest中采集数据,最后写入通过Log4net写入日志文件。

具体实现起来,应该很简单,高手可以略过了。

先看看如何使用吧,只需在Web.Config中加一条配置:

<configuration>
  <system.web>
     <httpModules>
        <add name="WSInvokeMonitorHttpModule" type="Hebmc.WebTools.WSInvokeMonitor.WSInvokeMonitorHttpModule,WSInvokeMonitor"/>
    </httpModules>
    <webServices>
        <soapExtensionTypes>
            <add type="Hebmc.WebTools.WSInvokeMonitor.SimpleWSInvokeMonitorExtension,WSInvokeMonitor"
                priority="1"
                group="0" />
        </soapExtensionTypes>
    </webServices>
 </system.web>
</configuration>

SoapExtension实现:

    public class SimpleWSInvokeMonitorExtension : SoapExtension
    {
        private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
        private WSInvokeInfo invokeInfo = new WSInvokeInfo();
        public override System.IO.Stream ChainStream(System.IO.Stream stream)
        {
            return stream;
        }         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;
                        //采集WebService方法名
                        this.invokeInfo.MethodName = message.MethodInfo.Name;
                        break;                     case SoapMessageStage.AfterSerialize:
                        break;                     case SoapMessageStage.BeforeDeserialize:
                        break;                         // About to call methods
                    case SoapMessageStage.AfterDeserialize:                         //采集时间
                        this.invokeInfo.EndInvokeTime = DateTime.Now;                         PageInfo pageInfo = (PageInfo)HttpContext.Current.Items[WSInvokeMonitorKey] ;
                        if(pageInfo != null)
                        {
                            //添加到Module记录
                            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) 
                {
                    case SoapMessageStage.BeforeDeserialize:
                        break;                     case SoapMessageStage.AfterDeserialize:
                        break;                     case SoapMessageStage.BeforeSerialize:
                        break;                     case SoapMessageStage.AfterSerialize:
                        break;                     default:
                        throw new Exception("No stage such as this");
                }             }
        }     }

HttpModule实现:

    public class WSInvokeMonitorHttpModule : IHttpModule    
    {
        private static ILog log  = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
        HttpApplication httpApp = null;         #region IHttpModule 成员         public void Init(HttpApplication webApp)
        {
            this.httpApp = webApp;             //注册事件 
            this.httpApp.BeginRequest+=new EventHandler(context_BeginRequest);
            this.httpApp.PreRequestHandlerExecute+=new EventHandler(httpApp_PreRequestHandlerExecute);
            this.httpApp.PreSendRequestContent+=new EventHandler(context_PreSendRequestContent);
            this.httpApp.EndRequest+=new EventHandler(context_EndRequest);
        }         public void Dispose()
        {
            this.httpApp.BeginRequest-=new EventHandler(context_BeginRequest);
            this.httpApp.PreSendRequestContent-=new EventHandler(context_PreSendRequestContent);
            this.httpApp.EndRequest-=new EventHandler(context_EndRequest);
        }         #endregion         private void context_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication webApp = sender as HttpApplication;
            if(webApp != null)
            {
                PageInfo pageInfo = null;
                
                //开始时,设置数据对象,将来采集到的数据都放在这里
                webApp.Context.Items[WSInvokeMonitorKey] = pageInfo = new PageInfo();                 //采集路径
                pageInfo.PageUri = webApp.Context.Request.Url.ToString();
            }
            
        }         private void httpApp_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpApplication webApp = sender as HttpApplication;
            if(webApp != null)
            {
                Page page = webApp.Context.Handler as Page;
                if(page != null)
                {
                    PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
                    if(pageInfo != null)
                    {
                        //采集处理类名,及时间
                        pageInfo.TypeName = page.GetType().FullName;
                        pageInfo.PreRequestHandlerExecuteTime = DateTime.Now;
                    }
                }             }
        }         private void context_PreSendRequestContent(object sender, EventArgs e)
        {
            HttpApplication webApp = sender as HttpApplication;
            if(webApp != null)
            {
                Page page = webApp.Context.Handler as Page;
                if(page != null)
                {
                    PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
                    if(pageInfo != null)
                    {
                        try
                        {
                            //采集时间
                            pageInfo.PreSendRequestContentTime = DateTime.Now;                             if(log.IsInfoEnabled)
                            {
                                //记日志
                                string xmlData = string.Empty;
                                XmlSerializer xs = new XmlSerializer(typeof(PageInfo));
                                StringBuilder sb = new StringBuilder();
                                using(MemoryStream ms = new MemoryStream())
                                {
                                    XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
                                    xtw.Formatting = Formatting.None;
                                    xs.Serialize(xtw, pageInfo);
                                                                         ms.Position = 0;                                     StreamReader sr = new StreamReader(ms, Encoding.UTF8);
                                    xmlData = sr.ReadToEnd();
                                }                                 TimeSpan tsExecute = pageInfo.EndRequestTime - pageInfo.BeginRequestTime;
                                log.InfoFormat("{0},{1},{2}MS,{3},{4},{5}", 
                                    pageInfo.BeginRequestTime, 
                                    pageInfo.TypeName, 
                                    tsExecute.TotalMilliseconds, 
                                    pageInfo.WSInvokeCount,
                                    pageInfo.PageUri, 
                                    xmlData);                             }
                        }
                        catch (System.Exception ex)
                        {
                            log.Error(ex);
                        }
                    }
                }
            }
        }         private void context_EndRequest(object sender, EventArgs e)
        {
            HttpApplication webApp = sender as HttpApplication;
            if(webApp != null)
            {
                Page page = webApp.Context.Handler as Page;
                if(page != null)
                {
                    PageInfo pageInfo = (PageInfo)webApp.Context.Items[WSInvokeMonitorKey];
                    if(pageInfo != null)
                    {
                        //采集时间
                        pageInfo.EndRequestTime = DateTime.Now;
                    }                 }
            }
        }     }

用到的数据类:

namespace Hebmc.WebTools.WSInvokeMonitor.Data
{
    [Serializable]
    public class PageInfo
    {
        private string typeName;
        private string pageUri;
        private DateTime beginRequestTime = DateTime.Now;
        private DateTime preRequestHandlerExecuteTime = DateTime.Now;
        private DateTime endRequestTime = DateTime.Now;
        private DateTime preSendRequestContentTime = DateTime.Now;
        private ArrayList wsInvokeInfoList = new ArrayList();         /// <summary>
        /// 类名
        /// </summary>
        public string TypeName
        {
            get { return typeName; }
            set { typeName = value; }
        }         /// <summary>
        /// 页面URI
        /// </summary>
        public string PageUri
        {
            get { return pageUri; }
            set { pageUri = value; }
        }         /// <summary>
        /// 开始时间
        /// </summary>
        public System.DateTime BeginRequestTime
        {
            get { return beginRequestTime; }
            set { beginRequestTime = value; }
        }         /// <summary>
        /// 开始处理时间
        /// </summary>
        public System.DateTime PreRequestHandlerExecuteTime
        {
            get { return preRequestHandlerExecuteTime; }
            set { preRequestHandlerExecuteTime = value; }
        }         /// <summary>
        /// 结束处理时间
        /// </summary>
        public System.DateTime EndRequestTime
        {
            get { return endRequestTime; }
            set { endRequestTime = value; }
        }         /// <summary>
        /// 向客户端发送数据开始时间
        /// </summary>
        public System.DateTime PreSendRequestContentTime
        {
            get { return preSendRequestContentTime; }
            set { preSendRequestContentTime = value; }
        }         /// <summary>
        /// 调用次数
        /// </summary>
        [XmlIgnore]
        public int WSInvokeCount
        {
            get
            {
                return this.wsInvokeInfoList.Count;
            }
        }         /// <summary>
        /// 该页面调用的WebService信息
        /// </summary>
        public WSInvokeInfo[] WSInvokeInfos
        {
            get
            {
                return (WSInvokeInfo[])wsInvokeInfoList.ToArray(typeof(WSInvokeInfo));
            }
            set
            {
                wsInvokeInfoList.AddRange(value);
            }
        }         /// <summary>
        /// 添加一个调用WebService日志
        /// </summary>
        /// <param name="info"></param>
        public void AppendInvokeInfo(WSInvokeInfo info)
        {
            wsInvokeInfoList.Add(info);
        }         /// <summary>
        /// 序列化需要
        /// </summary>
        public PageInfo()
        {}
    }     [Serializable]
    public class WSInvokeInfo
    {
        private string methodName;
        private DateTime beginInvokeTime = DateTime.Now;
        private DateTime endInvokeTime = DateTime.Now;         /// <summary>
        /// 函数名
        /// </summary>
        public string MethodName
        {
            get { return methodName; }
            set { methodName = value; }
        }         /// <summary>
        /// 开始调用时间
        /// </summary>
        public System.DateTime BeginInvokeTime
        {
            get { return beginInvokeTime; }
            set { beginInvokeTime = value; }
        }         /// <summary>
        /// 结束调用时间
        /// </summary>
        public System.DateTime EndInvokeTime
        {
            get { return endInvokeTime; }
            set { endInvokeTime = value; }
        }     }
}

OK了,这个方案还可以继续深入,可以使用SoapExtension把WebService层的采集到的数据,也拉到前端。这样便可以知道一个WebService方法执行几次数据库连接。嘿嘿。

http://www.cnblogs.com/evlon/archive/2009/05/22/1486866.html

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

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

    上一篇文章 "无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)"中,我们实现了监视每个页面的执行情况和调用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. Mysql源码目录结构

    Programs for handling SQL commands. The "core" of MySQL. These are the .c and .cc files in ...

  2. 使用git提交github代码

    新的项目的提交 touch README.md git init git add README.md git commit -m "first commit" git remote ...

  3. sql server 创建文件组,文件

    添加文件组:  --ADD FILEGROUP 增加文件组 ALTER DATABASE TestHekaton ADD FILEGROUP [Report] ALTER DATABASE TestH ...

  4. java_list,set,map集合

    一.集合定义 集合就是讲诺干用途相同.近似的“数据”结合成一个整体 集合从体系上分为三种 1.列表(List):List集合区分元素的顺序,允许包含相同的元素 2.集(set):Set集合不区分元素的 ...

  5. linux包之sysstat之sar命令

    要启动SAR,必须通过cron工具以周期性的间隔启动.安装sysstat包后,默认创建一个/etc/cron.d/sysstat文件,其默认内容为:# run system activity acco ...

  6. web的各种前端打印方法之CSS控制网页打印样式

    来源:http://www.jb51.net/web/70358.html CSS控制网页打印样式: 使用CSS控制打印样式,握刚刚使用时一塌糊涂,根本不知道CSS中的midia的作用是什么,问到别人 ...

  7. 内联样式自动出现,一般是js控制写入的

    内联样式自动出现,一般是js控制写入的

  8. 通过Profiles查看create语句的执行时间消耗 (转)

    一,查看profiles的状态值   1,查看profiles是否已经打开了,默认是不打开的.   mysql> show profiles;   Empty set (0.02 sec) my ...

  9. Message,MessageQueue,Looper,Handler详解+实例

    Message,MessageQueue,Looper,Handler详解+实例 原文地址 Android的Handler使用(这篇简单介绍Handler的使用) 一.几个关键概念 1.Message ...

  10. .Net分布式缓存应用实例:Couchbase

    转自:http://www.cnblogs.com/wu-jian Couchbase概述 Couchbase最早叫Membase,是由Memcached项目组的一些头目另立的山头. 2011年与Co ...