您的位置:首页 > 编程语言 > ASP

Asp.net 服务端缓存引发的一点思考

2012-09-03 22:30 435 查看
我们知道asp.net要经历以下事件

BeginRequest

AuthenticateRequest

PostAuthenticateRequest

AuthorizeRequest

PostAuthorizeRequest

ResolveRequestCache

PostResolveRequestCache

PostMapRequestHandler

AcquireRequestState

PostAcquireRequestState

PreRequestHandlerExecute
....IHttpHandler 类的 ProcessRequest 方法,真正处理请求的地方时一个比较耗时的处理

PostRequestHandlerExecute

eleaseRequestState

PostReleaseRequestState 事件。

UpdateRequestCache

PostUpdateRequestCache

EndRequest

  而在服务端我们缓存经常会用到OutputCache,之所以能用它只要是因为OutputCacheModule中有如下代码:



void IHttpModule.Init(HttpApplication app)
{
if (RuntimeConfig.GetAppConfig().OutputCache.EnableOutputCache)
{
app.ResolveRequestCache += new EventHandler(this.OnEnter);
app.UpdateRequestCache += new EventHandler(this.OnLeave);
}
}
同样只要看过OutputCacheModule源码的人都知道这里面面的代码比较难懂,为了提高性能,我们能否把读取缓存的时间往前推推到BeginRequest,一旦有缓存这个时候我们就返回数据结束输出流。那么什么时候设置缓存了?我们可以选着在ReleaseRequestState事件中处理,在这个处理中我们需要截获输出流的内容。

在本例中只是提出这种缓存的思想,在项目中运用需要注意的事情还很多。

首先我们需要实现缓存机制,这里我们用字典来存储数据永不过期。

public class Cache
{
static ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
public static void Add(string key, string value)
{
if (dict.ContainsKey(key))
{
dict[key] = value;

}
else
{
dict.TryAdd(key, value);
}
}
public static string Get(string key)
{
string result = string.Empty;
dict.TryGetValue(key, out result);
return result;
}
}


代码很简单吧,同样需要截获输出流的代码

public class PageFilter : Stream
{
Stream responseStream;
long position;
StringBuilder responseHtml;

public PageFilter(Stream inputStream)
{
responseStream = inputStream;
responseHtml = new StringBuilder();
}

#region Filter overrides
public override bool CanRead
{
get { return true; }
}

public override bool CanSeek
{
get { return true; }
}

public override bool CanWrite
{
get { return true; }
}

public override void Close()
{
responseStream.Close();
}

public override void Flush()
{
responseStream.Flush();
}

public override long Length
{
get { return 0; }
}

public override long Position
{
get { return position; }
set { position = value; }
}

public override long Seek(long offset, SeekOrigin origin)
{
return responseStream.Seek(offset, origin);
}

public override void SetLength(long length)
{
responseStream.SetLength(length);
}

public override int Read(byte[] buffer, int offset, int count)
{
return responseStream.Read(buffer, offset, count);
}
#endregion

#region Dirty work
public override void Write(byte[] buffer, int offset, int count)
{
HttpResponse response = HttpContext.Current.Response;
string charset = response.Charset ?? "utf-8";
string finalHtml = Encoding.GetEncoding(charset).GetString(buffer, offset, count);

int index = finalHtml.IndexOf("</html>");
if (index<1)
{
responseHtml.Append(finalHtml);
}
else
{
responseHtml.Append(finalHtml);
finalHtml = responseHtml.ToString();
byte[] data = Encoding.GetEncoding(charset).GetBytes(finalHtml);
/*缓存处理*/
string key = HttpContext.Current.Request.Url.ToString();
Cache.Add(key, finalHtml);
/*缓存处理*/
responseStream.Write(data, 0, data.Length);
}

}

#endregion
}


那么如何运用了?在Global.asax.cs文件中:

public override void Init()
{
base.Init();
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.ReleaseRequestState += new EventHandler(MvcApplication_ReleaseRequestState);
}

void MvcApplication_BeginRequest(object sender, EventArgs e)
{
string key = HttpContext.Current.Request.Url.ToString();
HttpResponse response = HttpContext.Current.Response;
string result = Cache.Get(key);
if (!string.IsNullOrEmpty(result))
{
response.Write(result);
((HttpApplication)sender).CompleteRequest();
}

}

void MvcApplication_ReleaseRequestState(object sender, EventArgs e)
{

HttpResponse response = HttpContext.Current.Response;
if (response.ContentType == "text/html")
{
response.Filter = new PageFilter(response.Filter);
}
}
运行结果,无论你运行多少次结果都如下



这种处理方式和OutputCache一样不用区分你的程序是否是mvc模式。在实际项目中我们可以用Memcached、Redis、AppFabric 来做分布式缓存。比如像凡客、京东某些页面就可以采用这种思想来实现,比你在页面或action任何地方读取缓存的效率要高出很多,当然效率高的代价就是它的适用范围比较窄,实际中往往不是缓存一个完整的整个页面内容,而只是缓存一部分。

欢迎大家拍砖
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: