您的位置:首页 > 理论基础 > 计算机网络

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

2014-03-15 22:55 197 查看
先简单介绍一下项目吧,我们这个项目是用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方法执行几次数据库连接。嘿嘿。

QQ:273352165 evlon#126.com 转载请注明出处。
http://www.cnblogs.com/evlon/archive/2009/05/22/1486866.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: