Thursday, January 27, 2011

HttpModule to check the performance of a (sharepoint) site

I want to share the code of a http module I made for checking the performance of the backend site creation process. The result indicates if the site will break down when its launched and used by tausends of people. You can leave this module in your solution and activate it everytime you have to check the performance of a webpart or control. The module is simply activated by inserting an entry in the web.config.

When you type perf=1 in the querystring (ex. http://mydomain.com/pages/default.aspx?perf=1) than a little yellow div will appear on the upper left corner, that displays the information.

Performance of the backend process


First we create a new class and implent the IHttpModule interface. We implement the init method, which is the starting point.There we have to create two delegates, that process the request.

In an other class we implement the PerformanceFilter to manipulate the outputstream of the request. Here we read the stream an place a div with the information when we find the </body> tag


1:  using System;  
2:  using System.Collections.Generic;  
3:  using System.Linq;  
4:  using System.Text;  
5:  using System.Web;  
6:  using System.Diagnostics;  
7:  using System.IO;  
8:  namespace MyProject.Intranet.SharePoint.CommonLib.HttpModules  
9:  {  
10:    /// <summary>  
11:    /// A http module to check the performance of a sharepoint site  
12:    /// The module is activated when you put perf=1 as parameter in the querystring  
13:    /// Autor: I.Bikmaz  
14:    /// </summary>  
15:    public class PerformanceMonitor : IHttpModule  
16:    {  
17:      /// <summary>  
18:      /// In this method the request is intercepted and the timer begins  
19:      /// </summary>  
20:      public void Init(HttpApplication context)  
21:      {  
22:        context.PreRequestHandlerExecute += delegate(object sender, EventArgs e)  
23:        {  
24:          //Set Page Timer Star  
25:          HttpContext requestContext = ((HttpApplication)sender).Context;  
26:          Stopwatch timer = new Stopwatch();  
27:          requestContext.Items["Timer"] = timer;  
28:          timer.Start();  
29:        };  
30:        context.PostRequestHandlerExecute += delegate(object sender, EventArgs e)  
31:        {  
32:          HttpContext httpContext = ((HttpApplication)sender).Context;  
33:          HttpResponse response = httpContext.Response;  
34:          Stopwatch timer = (Stopwatch)httpContext.Items["Timer"];  
35:          timer.Stop();          
36:          // Don't interfere with non-HTML responses  
37:          if (response.ContentType == "text/html")  
38:          {            
39:            bool addPerformanceHtml = httpContext.Request.Url.ToString().Contains("perf=1");  
40:            if (addPerformanceHtml)  
41:            {  
42:              double seconds = (double)timer.ElapsedTicks / Stopwatch.Frequency;  
43:              string result_time = string.Format("{0:F4} sec ", seconds);  
44:              response.Filter = new PerformanceFilter(response.Filter, result_time);              
45:            }  
46:          }  
47:        };  
48:      }  
49:      /// <summary>  
50:      /// Disposal  
51:      /// </summary>  
52:      public void Dispose()  
53:      {  
54:      }  
55:    }  
56:    /// <summary>  
57:    /// Filter to manipulate the output stream  
58:    /// </summary>  
59:    public class PerformanceFilter : MemoryStream  
60:    {  
61:      private Stream mStream;  
62:      private StreamWriter mStreamWriter;  
63:      private String mTime;  
64:      /// <summary>  
65:      /// Constructor  
66:      /// </summary>  
67:      /// <param name="stm">The stream to filter</param>  
68:      /// <param name="time">The time to display</param>  
69:      public PerformanceFilter(Stream stm, String time)  
70:      {  
71:        mStream = stm;  
72:        mStreamWriter = new StreamWriter(mStream, System.Text.Encoding.UTF8);  
73:        mTime = time;  
74:      }  
75:      /// <summary>  
76:      /// Writes the new stream  
77:      /// </summary>  
78:      /// <param name="buffer"></param>  
79:      /// <param name="offset"></param>  
80:      /// <param name="count"></param>  
81:      public override void Write(byte[] buffer, int offset, int count)  
82:      {  
83:        MemoryStream ms = new MemoryStream(buffer, offset, count, false);  
84:        StreamReader sr = new StreamReader(ms, System.Text.Encoding.UTF8);  
85:        String s;  
86:        while ((s = sr.ReadLine()) != null)  
87:        {  
88:          s = s.Trim();  
89:          if (s == "</body>")  
90:          {            
91:            mStreamWriter.Write(String.Format("<div style=\"padding:5px; background:yellow; width:110px; height:25px; position:absolute; left:0;top:0\">Page generated in {0}</div>", mTime));            
92:          }  
93:          mStreamWriter.WriteLine(s);  
94:        }  
95:        mStreamWriter.Flush();  
96:      }  
97:    }  
98:  }  

After adding code to your solution you have to activate the http module by adding a web.confog entry. In SharePoint 2010 you should add the entry at the bottom  of the modules tag:


 <modules runAllManagedModulesForAllRequests="true">  
  <remove name="AnonymousIdentification" />  
  <remove name="FileAuthorization" />  
  ....  
  <add name="PublishingHttpModule" ...  
  <add name="PerformanceHttpModule"   
   type="MyProject.Intranet.SharePoint.CommonLib.HttpModules.PerformanceMonitor, MyProject.Intranet.SharePoint.CommonLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxx" />  
 </modules>  

No comments: