做服务端的程序,经常要监控服务的性能,比如某个方法每秒执行了多少次了呀?某个方法同一时间有多少个并发方法啦?某个对象在内存里有多少个实例啦?执行某个操作的平均操作时间啦等等。.net提供了创建自定义性能计数器的API来让我们方便的实现这些需求,我改造了一下《.net企业应用高级编程》里的WEO框架的计数器部分,让大家方便的创建自己的计数器,原来是.net 1.0的,用的反射,我移植到了.net 2.0,改用的泛型,性能会好一些。先来看看大概思路。

要想创建自定义的计数器,先得实现IPerfCounterProvider接口,CreateCounters方法声明要创建的计数器,CountersCreated方法把创建的计数器赋值给本类的成员,PerformanceObjectName返回要创建自定义计数器的分类名。
PerfCounterFactory主要用来创建一个IPerfCounterProvider的实例,它有个GetCounters的泛型方法用来创建一个IPerfCounterProvider的实例,CreateCounters方法用来实际的创建性能计数器,另两个AddPerfCounter方法和Find方法是让IPerfCounterProvider的两个方法用的,下面的例子里会有。
PerfCounter是一个实体类,保存每个计数器的名称,帮助,类型。
好,我们要监控一个web服务的性能,这个Web服务提供相乘和相加的服务,我们要知道这个Web服务的总请求数,每秒调用次数,并发调用数,每个web方法每秒的调用次数,创建计数器如下,关于计数器的类型,及性能计数器的相关内容,请查看MSDN,计数器类型有总量计数器,平均计数器,速率计数器,并发计数器等,分别适用于不同的需求。
public class MathServicePerfCounter : IPerfCounterProvider
{
static MathServicePerfCounter _instance =
PerfCounterFactory.GetCounters<MathServicePerfCounter>();
public static MathServicePerfCounter Instance
{
get
{
return _instance;
}
}
public PerformanceCounter TotalOfRequest;
public PerformanceCounter RateOfRequest;
public PerformanceCounter RateOfAddition;
public PerformanceCounter RateOfMultiplication;
public PerformanceCounter CountOfCurrentRequest;
const string TotalOfRequestStr = "Total # req";
const string RateOfRequestStr = "req/sec";
const string RateOfAdditionStr = "Addition/sec";
const string RateOfMultiplicationStr = "Multiplication/sec";
const string CountOfCurrentRequestStr = "current # req";
IPerfCounterProvider 成员
}

从以上可以看到,接口实现里要做点儿啥,MathServicePerfCounter怎么用,你要想创建自己的计数器,比猫画虎就OK了,咱们开始创建一个Web服务,添加俩web方法
[WebMethod]
public int Addition(int a, int b)
{
MathServicePerfCounter.Instance.RateOfAddition.Increment();
Random r = new Random();
Thread.Sleep(r.Next(500, 2000));
return a + b;
}
[WebMethod]
public int Multiplication(int a, int b)
{
MathServicePerfCounter.Instance.RateOfMultiplication.Increment();
Random r = new Random();
Thread.Sleep(r.Next(500, 2000));
return a * b;
}

为了模拟真实环境,每个方法随机休眠几秒,然后右键点那个服务,在浏览器测试一下那个服务,看看能浏览不?然后在开始运行里输入perfmon,添加计数器里看看有没有咱们的MathServicePerfCounter计数器,反正我这里有。

对了,global.asax里加上如下代码,为了监控每秒请求和总请求量及并发请求量
void Application_BeginRequest(object sender, EventArgs e)
{
MathServicePerfCounter.Instance.CountOfCurrentRequest.Increment();
MathServicePerfCounter.Instance.RateOfRequest.Increment();
MathServicePerfCounter.Instance.TotalOfRequest.Increment();
}
void Application_EndRequest(object sender, EventArgs e)
{
MathServicePerfCounter.Instance.CountOfCurrentRequest.Decrement();
}

服务有了,咱得有单元测试呀,在这个Web服务上点右键,创建一个单元测试,vs会自动给你创建一个测试项目,项目的名字你可以自己指定,然后会自动给你添加一个Web引用,然后自动生成一个叫MathService.asmxTest.cs的测试类,里面给你生成两个测试方法,修改一下初始值及期望值,去除Assert.Inconclusive语句,最后如下。

/// <summary>
///Addition (int, int) 的测试
///</summary>
[TestMethod()]
public void AdditionTest()
{
MathService target = new MathService(); // TODO: 使用 [AspNetDevelopmentServer] 和 TryUrlRedirection() 自动启动并绑定 Web 服务。
int a = 5; // TODO: 初始化为适当的值
int b = 6; // TODO: 初始化为适当的值
int expected = 11;
int actual;
actual = target.Addition(a, b);
Assert.AreEqual(expected, actual, "MathServiceTest.localhost.MathService.Addition 未返回所需的值。");
}
/// <summary>
///Multiplication (int, int) 的测试
///</summary>
[TestMethod()]
public void MultiplicationTest()
{
MathService target = new MathService(); // TODO: 使用 [AspNetDevelopmentServer] 和 TryUrlRedirection() 自动启动并绑定 Web 服务。
int a = 5; // TODO: 初始化为适当的值
int b = 6; // TODO: 初始化为适当的值
int expected = 30;
int actual;
actual = target.Multiplication(a, b);
Assert.AreEqual(expected, actual, "MathServiceTest.localhost.MathService.Multiplication 未返回所需的值。");
}
