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

    先简单介绍一下项目吧,我们这个项目是用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中加一条配置:

Code
<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实现:

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 thisdot.gif");
                }

            }
            
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 thisdot.gif");
                }

            }
        }


    }

 

HttpModule实现:

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;
                    }


                }
            }
        }

    }

 

用到的数据类:

Code
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();

        
/// 
        
/// 类名
        
/// 

        public string TypeName
        {
            
get { return typeName; }
            
set { typeName = value; }
        }

        
/// 
        
/// 页面URI
        
/// 

        public string PageUri
        {
            
get { return pageUri; }
            
set { pageUri = value; }
        }

        
/// 
        
/// 开始时间
        
/// 

        public System.DateTime BeginRequestTime
        {
            
get { return beginRequestTime; }
            
set { beginRequestTime = value; }
        }

        
/// 
        
/// 开始处理时间
        
/// 

        public System.DateTime PreRequestHandlerExecuteTime
        {
            
get { return preRequestHandlerExecuteTime; }
            
set { preRequestHandlerExecuteTime = value; }
        }

        
/// 
        
/// 结束处理时间
        
/// 

        public System.DateTime EndRequestTime
        {
            
get { return endRequestTime; }
            
set { endRequestTime = value; }
        }


        
/// 
        
/// 向客户端发送数据开始时间
        
/// 

        public System.DateTime PreSendRequestContentTime
        {
            
get { return preSendRequestContentTime; }
            
set { preSendRequestContentTime = value; }
        }

        
/// 
        
/// 调用次数
        
/// 

        [XmlIgnore]
        
public int WSInvokeCount
        {
            
get
            {
                
return this.wsInvokeInfoList.Count;
            }
        }


        
/// 
        
/// 该页面调用的WebService信息
        
/// 

        public WSInvokeInfo[] WSInvokeInfos
        {
            
get
            {
                
return (WSInvokeInfo[])wsInvokeInfoList.ToArray(typeof(WSInvokeInfo));
            }
            
set
            {
                wsInvokeInfoList.AddRange(value);
            }
        }

        
/// 
        
/// 添加一个调用WebService日志
        
/// 

        
/// 
        public void AppendInvokeInfo(WSInvokeInfo info)
        {
            wsInvokeInfoList.Add(info);
        }

        
/// 
        
/// 序列化需要
        
/// 

        public PageInfo()
        {}
    }

    [Serializable]
    
public class WSInvokeInfo
    {
        
private string methodName;
        
private DateTime beginInvokeTime = DateTime.Now;
        
private DateTime endInvokeTime = DateTime.Now;

        
/// 
        
/// 函数名
        
/// 

        public string MethodName
        {
            
get { return methodName; }
            
set { methodName = value; }
        }

        
/// 
        
/// 开始调用时间
        
/// 

        public System.DateTime BeginInvokeTime
        {
            
get { return beginInvokeTime; }
            
set { beginInvokeTime = value; }
        }

        
/// 
        
/// 结束调用时间
        
/// 

        public System.DateTime EndInvokeTime
        {
            
get { return endInvokeTime; }
            
set { endInvokeTime = value; }
        }




    }
}

 

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

你可能感兴趣的:(无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一))