本文将叙述如何计算出ASP.NET页面执行所需要的时间,当项目较大的时候有时候可能出现一些莫明其妙的错误,这可能是性能上的瓶颈或者是某些BUG引发的(比如<img src="" />,会引起两次访问你的服务资源),这时我们需要计算出每个时间执行的时间以便排查出引发项目出现性能异常的页面。
第一步:建立所有页面的基类
PageBase.cs
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Collections.Generic; using System.Text; using System.IO; /// <summary> /// PageBase 的摘要说明 /// </summary> public class PageBase : Page { public PageBase() { // // TODO: 在此处添加构造函数逻辑 // } #region Overriden protected override void OnInit(EventArgs e) { base.OnInit(e); //计算时间执行时间 if (this.MeasureExecutionTime) { watch = new System.Diagnostics.Stopwatch(); watch.Start(); this.RecordTimeStamp("页面开始执行……"); } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); } protected override void OnPreRenderComplete(EventArgs e) { base.OnPreRenderComplete(e); if (this.MeasureExecutionTime) { this.RecordTimeStamp("Page execution complete..."); watch.Stop(); Control addExecutionTo = this.Form; if (addExecutionTo == null) addExecutionTo = this; addExecutionTo.Controls.Add(new LiteralControl("<br /><br />")); StringBuilder timestampsOutput = new StringBuilder(50 * this.ExcutionTimeStamps.Count); for (int i = 0; i < this.ExcutionTimeStamps.Count; i++) timestampsOutput.AppendFormat("<b>Timestamp {0}</b>: {1:N0} ms ({2})<br />{3}", i + 1, this.ExcutionTimeStamps[i].TimeStamp, this.ExcutionTimeStamps[i].Description, Environment.NewLine); addExecutionTo.Controls.Add(new LiteralControl(timestampsOutput.ToString())); } } #endregion #region Members #endregion #region FindControlRecursive 迭代查找控件 protected virtual Control FindControlRecursive(string id) { return FindControlRecursive(id, this); } /// <summary> /// 迭代查找控件 /// </summary> /// <param name="id">查找控件的编号</param> /// <param name="parent">控件容器</param> /// <returns>Control</returns> protected virtual Control FindControlRecursive(string id, Control parent) { // if parent is the control we're looking for, return it if (string.Compare(parent.ID, id, true) == 0) return parent; //search through children foreach (Control child in parent.Controls) { Control match = FindControlRecursive(id, child); if (match != null) return match; } //if we reach here then no control width id was found. return null; } #endregion #region ExecutionTime 执行时间 /// <summary> /// 是否开启计算页面计算时间 /// </summary> public virtual bool MeasureExecutionTime { get { object o = ViewState["MeasureExecutionTime"]; return o == null ? false : (bool)o; } set { ViewState["MeasureExecutionTime"] = value; } } private System.Diagnostics.Stopwatch watch = null; private List<TimeStampInfo> timeStamps = null; /// <summary> /// 页面执行时间集合 /// </summary> protected virtual List<TimeStampInfo> ExcutionTimeStamps { get { if (timeStamps == null) timeStamps = new List<TimeStampInfo>(); return timeStamps; } } /// <summary> /// 记录页面执行时间 /// </summary> /// <param name="desc"></param> protected virtual void RecordTimeStamp(string desc) { if (watch == null) throw new ArgumentException("要记录页面的执行时间 MeasureExecutionTime 必须设置为 true."); ExcutionTimeStamps.Add(new TimeStampInfo(watch.ElapsedMilliseconds,desc)); } #endregion }
首先用一个变量MeasureExecutionTime来保存页面是否需要计算出执行的时间,然后重写页面的OnInit事件 ,当需要计算页面执行的时间则启动Stopwatch。
最后在OnPreRenderComplete中输出计算的结果。
第二步:建立需要计算页面执行时间的页面
其页面的测试如下:
Default.aspx.cs
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class _Default :PageBase { protected void Page_Init(object sender, EventArgs e) { base.MeasureExecutionTime = true; } protected void Page_Load(object sender, EventArgs e) { // Record timestamp base.RecordTimeStamp("Starting long running process"); // Do long running process Random rnd = new Random(); System.Threading.Thread.Sleep(rnd.Next(1000) + 1000); if (!IsPostBack) { DataTable dt = new DataTable(); dt.Columns.Add("ID"); dt.Columns.Add("Name"); for (int i = 0; i < 20; i++) { DataRow dr = dt.NewRow(); dr["ID"] = i; dr["Name"] = "Name" + i.ToString(); dt.Rows.Add(dr); dt.AcceptChanges(); } gv.DataSource = dt; gv.DataBind(); } // Record timestamp base.RecordTimeStamp("Completed long running process"); } }