A nice feature of Asp.net is to monitor the performance of a web
application using PerformanceCounter. This class is under
System.Diagnostics namespace and provides helpful features for
implementing counters that can be useful for monitoring site activity.
We can observe the counter status from the Performance tool in Administrative Tools of the operating system.
So, let us create a custom performance counter.
Firstly, we will create an abastract class which will be the base
class for all our performance counters for the current web
application.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Web;
namespace MyApp.BLL.Performance
{
public abstract class Counter
{
private const string _categoryName = "MyApp Counters";
protected abstract string CounterName
{
get;
}
public int Count
{
get
{
PerformanceCounterPermission permission = new
PerformanceCounterPermission(PerformanceCounterPermissionAccess.Administer,
Environment.MachineName, _categoryName);
permission.Assert();
if (PerformanceCounterCategory.Exists(_categoryName))
{
PerformanceCounter counter = new PerformanceCounter(_categoryName, CounterName);
int count = Convert.ToInt32(counter.RawValue);
counter.Close();
PerformanceCounterPermission.RevertAll();
return count;
}
else
return 0;
}
}
public int Increase()
{
PerformanceCounterPermission permission = new
PerformanceCounterPermission(PerformanceCounterPermissionAccess.Administer,
Environment.MachineName, _categoryName);
permission.Assert();
if (PerformanceCounterCategory.Exists(_categoryName))
{
PerformanceCounter counter = new PerformanceCounter(_categoryName, CounterName, false);
long currentCount = counter.Increment();
PerformanceCounterPermission.RevertAll();
return Convert.ToInt32(currentCount);
}
else
{
PerformanceCounterCategory.Create(_categoryName, _categoryName,
PerformanceCounterCategoryType.SingleInstance, CounterName, CounterName);
PerformanceCounter counter = new PerformanceCounter(_categoryName, CounterName, false);
counter.RawValue = 1;
PerformanceCounterPermission.RevertAll();
return Convert.ToInt32(counter.RawValue);
}
}
public int Decrease()
{
PerformanceCounterPermission permission = new
PerformanceCounterPermission(PerformanceCounterPermissionAccess.Administer,
Environment.MachineName, _categoryName);
permission.Assert();
if (PerformanceCounterCategory.Exists(_categoryName))
{
PerformanceCounter counter = new PerformanceCounter(_categoryName, CounterName, false);
long currentCount = 0;
if (counter.RawValue > 0)
{
currentCount = counter.Decrement();
}
PerformanceCounterPermission.RevertAll();
return Convert.ToInt32(currentCount);
}
else
{
PerformanceCounterCategory.Create(_categoryName, _categoryName, PerformanceCounterCategoryType.SingleInstance,
CounterName, CounterName);
PerformanceCounter counter = new PerformanceCounter(_categoryName, CounterName, false);
counter.RawValue = 0;
PerformanceCounterPermission.RevertAll();
return Convert.ToInt32(counter.RawValue);
}
}
}
}
We will override the CounterName property in every child class, for example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace MyApp.BLL.Performance
{
public sealed class UserLoginCounter : Counter
{
protected override string CounterName
{
get
{
return "Logged User Count";
}
}
}
}
now we can use the counter in an aspx page like the following:
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Linkmate.BLL.Performance;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
UserLoginCounter counter = new UserLoginCounter();
tbxCount.Text = counter.Count.ToString();
}
}
protected void UserEnter_Click(object sender, EventArgs e)
{
UserLoginCounter counter = new UserLoginCounter();
tbxCount.Text = counter.Increase().ToString();
}
protected void UserExit_Click(object sender, EventArgs e)
{
UserLoginCounter counter = new UserLoginCounter();
tbxCount.Text = counter.Decrease().ToString();
}
}
One important point to note about the PerformanceCounter is, though
we have assigned PerformanceCounterPermission, still we will not be
able to access the registry unless the user group accessing the
application has right permission to do so. It will raise an exception:
System.UnauthorizedAccessException: Access to the registry key 'Global' is denied.
A solution to this problem has been given here
a snapshot of that article is (in case the page is not available later on):
Windows 2003, Windows XP x64 Edition, and
Vista
require that the user be part of the Performance Monitor Users group to read
performance counter data. Simply adding your non admin user to this group will
fix this problem.
Accessing counters remotely is another story though. On
Windows 2003, Windows XP x64 Edition, and Vista
you still must be part of the Performance Monitor Users group on the remote
machine but there is a problem with the PerformanceCounter class where it tries
to read some registry keys on the remote machine that a non admin users do not
have access to. To give your user read access to these keys without having to be
an admin on the remote machine complete the following steps on the remote
machine:
- Open the Registry Editor by going to the Start Menu
and selecting Run…, then type “regedit”, and click the OK button.
- Navigate to the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg
registry key.
- Right click on the "winreg" key and select
Permissions. Add users or groups to which you want to grant Read access.
- Exit Registry Editor and restart Windows.
For more explanation on this process see
http://support.microsoft.com/?kbid=153183.
Posted
03-16-2009 10:25 AM
by
Jalal