先简单介绍一下项目吧,我们这个项目是用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. android语言适配

    虽然我们现在做的app基本只在国内使用,所以只需要中文,但是我们要把眼光放长远一点,以后我们的APP发展到了国外呢,所以我们就要做语言适配了   很简单 在res目录下,右键  New Resourc ...

  2. 怎么用OCR图文识别软件在MS Office中创建PDF文件

    ABBYY PDF Transformer+是一款可创建.编辑及将PDF文件转换为其他可编辑格式的OCR图文识别软件,不仅可以从纸质文档.图像文件和任何其他流行格式创建PDF文件(相关文章请参考如何从 ...

  3. Onload,Onunload,onbeforeunload,$(window).load(function() {})和$(document).ready(function(){})

    Onload,$(window).load(function() {}):元素都加载完毕,才可以执行. $(document).ready(function(){}):不一定要等所有的js和图片加载完 ...

  4. sql server 如何在一个数据库中操作另一个数据库中的数据

    INSERT INTO T1 SELECT   * FROM      OPENDATASOURCE(          'SQLOLEDB',          'Data Source=Serve ...

  5. Windows帐户类型

    摘自:http://blog.csdn.net/shineorrain/article/details/18181707 LocalSystem   账户  LocalSystem是预设的拥有本机所有 ...

  6. ios 企业发布

    ios 1. 支持的tls 协议 1.2 windows server 默认没有启用 检测的网站: https://www.ssllabs.com/ssltest 解决的方法: IIS crypto ...

  7. AMD规范:define和require的区别

    define和require在依赖处理和回调执行上都是一样的,不一样的地方是define的回调函数需要有return语句返回模块对象(注意是对象),这样define定义的模块才能被其他模块引用:req ...

  8. 200多个js技巧代码

    1.文本框焦点问题 onBlur:当失去输入焦点后产生该事件 onFocus:当输入获得焦点后,产生该文件 Onchange:当文字值改变时,产生该事件 Onselect:当文字加亮后,产生该文件 & ...

  9. 使用CAJViewer 提取PDF文件中的文字

    使用 CAJViewer 7.2 软件,把pdf格式的文件提取出文字. 操作步骤参考:http://jingyan.baidu.com/article/d45ad148cd06e469552b800f ...

  10. [原]网络库libevent在Visual Studio中的使用方法

    libevent是一个事件触发的网络库,适用于windows.linux.bsd等多种平台,内部使用select.epoll.kqueue等系统调用管理事件机制.著名分布式缓存软件memcached也 ...