来源: http://www.cnblogs.com/keepsilence/archive/2009/07/23/1529199.html
因为访问量大,做页面浏览量的时候不能直接操作库;用文件来记录的话,虽然减缓了数据库的压力但是对服务器I/O却是一个考验;而缓存正是.Net的一大优势,所以想出HttpHandler结合Cache来减缓I/O操作,这样I/O跟数据库的压力都解决了!
首先创建统计类库
1.创建CounterHelper统计类
using System;
using System.Web;
using System.Web.Caching;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;
using System.IO;
namespace MYSpace.Counter
{
/// <summary>
/// Counter 的摘要说明。
/// </summary>
public class CounterHelper
{
private int _Hits = 0; //累计的点击数
private string _FileName = "";
private string FilePth = string.Empty;
private string ErrorLogFilePth = string.Empty;
private int[] HitsArr = {-1,0,0}; //HitsArr[0]表示总的点击数HitsArr标识昨天的点击数HitsArr表示今天的点击数
CacheItemRemovedCallback onRemove = null;//CacheItemRemovedCallback对象
private string CacheName = "UpdateHitsForExpired";//缓存名称
private object LockForAddHits = new object();//LockForAddHits锁
private object LockForItemRemovedFromCacheHits = new object();//ItemRemovedFromCacheHits 锁
/**//// <summary>
/// 构造函数
/// </summary>
public CounterHelper(string filename)
{
_FileName = filename;
CacheName = filename;
HttpContext ctx = HttpContext.Current;
FilePth = ctx.Server.MapPath("~/" + _FileName + ".txt");
ErrorLogFilePth = ctx.Server.MapPath("~/" + _FileName + ".txt");
LoadHits();
}
/**//// <summary>
/// 将累计点击数保存到全局变量,当它达到一定量时保存到文本文件,并清空
/// </summary>
public void AddHits()
{
lock(LockForAddHits)
{
if( Hits != 0 )
{
Add();
if(Hits > 200 )
{
//--移除
HttpRuntime.Cache.Remove(CacheName);
}
}
else
{
onRemove = new CacheItemRemovedCallback(ItemRemovedFromCache);
HttpRuntime.Cache.Insert(
CacheName,
"This Object For Expired",
null,
DateTime.Now.AddSeconds(5) ,
TimeSpan.Zero,
System.Web.Caching.CacheItemPriority.Normal,
onRemove
);
Add();
}
}
}
/**//// <summary>
/// 保存到文本文件
/// </summary>
/// <param name="AllId"></param>
private void SaveHitsToFile(int hits)
{
string hitsinfo = string.Empty;
DateTime LastWriteTime = File.GetLastWriteTime(FilePth);
if((DateTime.Today - LastWriteTime).TotalDays >0 )
{
//--表示今天第一次写数据
HitsArr[1] = HitsArr[2];//--将当前累计的点击数赋给昨天的点击数
HitsArr[2] = hits;//--设置今天的点击数
using(StreamWriter streamWriter = new StreamWriter(FilePth,false) )
{
streamWriter.Write(string.Format("{0},{1},{2}",HitsArr[0] + hits,HitsArr[1] ,hits));
streamWriter.Flush();
}
}
else
{
using(StreamWriter streamWriter = new StreamWriter(FilePth,false) )
{
streamWriter.Write(string.Format("{0},{1},{2}",HitsArr[0] + hits,HitsArr[1], HitsArr[2] + hits));
streamWriter.Flush();
}
}
}
/**//// <summary>
/// 当缓存被移除或过期是触发的回调事件
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="reason"></param>
private void ItemRemovedFromCache(string key, object value,CacheItemRemovedReason reason)
{
try
{
//清空并写到文本文件
#region
int hits = 0;;
lock(LockForItemRemovedFromCacheHits)
{
hits = Hits;
HitsArr[0] += hits;
HitsArr[2] += hits;
Hits = 0;
}
if(hits == 0)
{
return;
}
else
{
SaveHitsToFile(hits);
}
#endregion
}
catch(Exception ex)
{
using(StreamWriter streamWriter = new StreamWriter(ErrorLogFilePth,false) )
{
streamWriter.Write(string.Format("时间:{0}/r/n描述信息:{1}/r/n",DateTime. Now,ex.Message));
streamWriter.Flush();
}
}
}
/**//// <summary>
/// 获取所有的点击数
/// </summary>
public int AllHits
{
get
{
return HitsArr[0] + Hits;
}
}
/**//// <summary>
/// 获取昨天点击数
/// </summary>
public int YesterdayHits
{
get
{
return HitsArr[1];
}
}
/**//// <summary>
/// 获取今天点击数
/// </summary>
public int TodayHits
{
get
{
return HitsArr[2] + Hits;
}
}
/**//// <summary>
/// 加载点击数
/// </summary>
private void LoadHits()
{
if (HttpRuntime.Cache[CacheName] == null)
{
HttpContext ctx = HttpContext.Current;
if (!File.Exists(FilePth))
{
//--第一次使用
using (StreamWriter streamWriter = new StreamWriter(FilePth))
{
streamWriter.Write(string.Format("{0},{1},{2}", 0, 0, 0));
streamWriter.Flush();
}
HitsArr[0] = 0;
HitsArr[1] = 0;
HitsArr[2] = 0;
}
else
{
string hitsinfo = string.Empty;
using (StreamReader objStreamReader = new StreamReader(FilePth))
{
hitsinfo = objStreamReader.ReadLine();
}
if (hitsinfo != "")
{
string[] arr = hitsinfo.Split(',');
HitsArr[0] = Convert.ToInt32(arr[0]);//全部
HitsArr[1] = Convert.ToInt32(arr[1]);//昨天
HitsArr[2] = Convert.ToInt32(arr[2]);//今天
}
else
{
HitsArr[0] = 0;
HitsArr[1] = 0;
HitsArr[2] = 0;
}
}
HttpRuntime.Cache["b" + CacheName] = HitsArr;
}
else
{
HitsArr = (int[])HttpRuntime.Cache["b" + CacheName];
//HitsArr[0] += 1;
//HitsArr[2] += 1;
}
}
/**//// <summary>
/// 获取累计的点击数
/// </summary>
private int Hits
{
get
{
return _Hits;
}
set
{
_Hits = value;
}
}
/**//// <summary>
/// 累加
/// </summary>
/// <param name="id"></param>
private void Add()
{
if(HitsArr[2]<14000)
{
//_Hits = _Hits + new Random(DateTime.Now.Second).Next(60,80);
_Hits = _Hits + 1;
}
else
{
_Hits = _Hits + 1;//_Hits = _Hits + new Random(DateTime.Now.Second).Next(2,8); 传回指定范围的随机数
}
}
/**//// <summary>
/// 文件名
/// </summary>
/// <summary>
/// 获取文件名
/// </summary>
public string FileName
{
get { return _FileName; }
set { _FileName = value; }
}
}
}
2.创建HttpHandler
<%@ WebHandler Language="C#" class="HttpHandler" %>
using System;
using System.Web;
using System.Text.RegularExpressions;
namespace MYSpace.Counter
{
/// <summary>
/// HitsHandler 的摘要说明。
/// </summary>
public class CounterHandler : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
CounterHelper objCounterHelper = new CounterHelper(ctx.Request.QueryString["id"].ToString());
objCounterHelper.AddHits();
ctx.Response.Write(string.Format("document.write('页面访问量:{0} 昨日:{1} 今日:{2} id :{3}')", objCounterHelper.AllHits, objCounterHelper.YesterdayHits, objCounterHelper.TodayHits, ctx.Request.Url.AbsoluteUri));
}
public bool IsReusable
{
get
{ return false; }
}
}
}
生成dll后创建一个Website,然后把dll引用进来!
接着在web.config里面添加配置:
<httpHandlers>
<add verb="*" path="count.aspx" type="MYSpace.Counter.CounterHandler,MYSpace.Counter" />
</httpHandlers>
最后在web页面调用就ok了。页面代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
<SCRIPT LANGUAGE="JavaScript" src='count.aspx?id=o4'></SCRIPT>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
这里只介绍到写入文件,如果想写入库里面,直接读取文件里的数值就搞定!