« Previous Next »

Thread: My Cache HttpModule and Memory Leaks

Last post 11-12-2009 8:35 AM by Serge2k. 2 replies.

Average Rating Rate It (5)

RSS

Page 1 of 1 (3 items)

Sort Posts:

  • 10-19-2009, 10:25 AM

    • Serge2k
    • Not Ranked
    • Joined on 07-02-2009, 8:46 AM
    • Posts 6

    My Cache HttpModule and Memory Leaks

    Hello. I have written my own cache extension. It works fine but i some time ago memory leaks appeared. One of the possible reasons is my wonderfull cache. :) Please take a look at the sources and say wheather i am doing everything right.

    Is it needed to detach PreRequestHandlerExecute event?

    cont.PreRequestHandlerExecute -= new EventHandler(OnPreRequestHandlerExecute);  

    How not to let asp.net execute the code of the page after the cached data is passed to the output. Is this correct?

    (source as HttpApplication).CompleteRequest();

    Response.End(); 

     

    Thank a lot.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Web;
    using System.Text.RegularExpressions;
    using System.IO;
    using System.Xml;

    namespace HttpCache

    {

    public class CacheModule : IHttpModule

    {

    #region IHttpModule Members

    private HttpApplication cont = null;

    public void Dispose()

    {

    cont.PreRequestHandlerExecute -= new EventHandler(OnPreRequestHandlerExecute);

    Server = null;

    Request = null;

    Response = null;

    cont = null;

    CacheConfigDocument = null;

    return;

    }

    public void Init(HttpApplication context)

    {

    cont = context; context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute);

    }

    #endregion

    private HttpServerUtility Server;
    private HttpRequest Request;private HttpResponse Response;
    private String HostPath;private String CachePath;
    private String LogFile;private FileInfo ScriptFile;
    private String ScriptPath;
    private XmlDocument CacheConfigDocument = new XmlDocument();

    public void OnPreRequestHandlerExecute(object source, EventArgs events)
    {

    try

    {

    if (!InitApplication((HttpApplication)source)) return;

    //

    if (!ScriptFile.FullName.ToLower().EndsWith(".aspx")) return;Boolean NeedFresh = false;
    Boolean NotAllHits = false;

     

    //

    ScriptPath = Request.ServerVariables["URL"].Substring(0, Request.ServerVariables["URL"].LastIndexOf("/") + 1);

    // node

    XmlNode RuleNode = GetRuleNode(ScriptPath);

    //

    TimeSpan Timeout = TimeSpanFromString(RuleNode.SelectSingleNode("timeout").InnerText);

    //

    String Params = GetParams(Request.ServerVariables["QUERY_STRING"], ref Timeout, ref NeedFresh);

    //

    FileInfo CacheFile = new FileInfo(GetCacheFileName(Request.ServerVariables["HTTP_X_ORIGINAL_URL"] ?? Request.ServerVariables["URL"], Params)); Boolean IsCacheFileValid = DateTime.Now.Subtract(CacheFile.LastWriteTime) < Timeout;

    // , 5

    if (!NeedFresh && CacheFile.Exists && !IsCacheFileValid && CacheFile.LastAccessTime.Second < 2)

    {

    DateTime access_date = CacheFile.LastAccessTime;

    NotAllHits = true;

    CacheFile.LastAccessTime = access_date.AddSeconds(1);

    }

    //

    if (!NeedFresh && CacheFile.Exists && (DateTime.Now.Subtract(CacheFile.LastWriteTime) < Timeout/*NotAllHits || IsCacheFileValid*/))

    {

    try

    {

    using(StreamReader sr = new StreamReader(CacheFile.FullName,Encoding.GetEncoding(1251)))

    {

    string Content = sr.ReadToEnd();if (!Content.Contains("<!--siteerror-->") && Content != "" )

    {

    Response.Write(Content);

    (source as HttpApplication).CompleteRequest();

    Response.End();

    return;

    }

    else NeedFresh = true;

    }

    }

    catch { NeedFresh = true; }

    }

    else NeedFresh = true;

    //

    if (NeedFresh && Timeout > TimeSpan.Zero)

    {

    Response.Filter = new CacheFilter(Response.Filter, CacheFile, Request.ServerVariables["HTTP_X_ORIGINAL_URL"] ?? Request.ServerVariables["URL"]);

    }

    }

    catch (Exception ex) { Log("Root", ex); }

    }

    //get parameters from querystring
    private
    string GetParams(string QueryString, ref TimeSpan Timeout, ref Boolean NeedFresh) {}

    //read cache rools for current script path  
    private XmlNode GetRuleNode(String ScriptPath) {}

    //get cache file name
    private
    string GetCacheFileName(String sURL, String sParameters) {}

    //reading cache life time
    private TimeSpan TimeSpanFromString(string value) {}

    private bool InitApplication(HttpApplication Application)

    {

    try

    {

    Server = Application.Context.Server;

    Request = Application.Context.Request;

    Response = Application.Context.Response;

    HostPath = Server.MapPath("/");

    CachePath = HostPath + "cache";

    ScriptFile = new FileInfo(Server.MapPath(Request.ServerVariables["URL"]));

    LogFile = CachePath + @"\logs\" + DateTime.Now.ToString("yyyy_MM_dd_HH") + ".txt";

    if (!Directory.Exists(CachePath + @"\logs")) Directory.CreateDirectory(CachePath + @"\logs");

    String CacheConfigFile = HostPath + @"cacheconfig.xml";

    CacheConfigDocument.Load(CacheConfigFile);

    return true;

    }

    catch (Exception ex) { Log("InitApplication", ex); }return false;

    }

    public class CacheFilter : Stream

    {

    Stream stream; FileInfo CacheFile;

    //StreamWriter cacheWriter = null;

    String Content = "";

    String OriginalUrl = "";

    DateTime CacheFileLastModifiedData;public CacheFilter(Stream stream, FileInfo CacheFile, String OriginalUrl)

    {

    this.stream = stream;

    this.CacheFile = CacheFile;

    this.CacheFileLastModifiedData = CacheFile.Exists ? CacheFile.LastWriteTime : DateTime.Now;

    this.OriginalUrl = OriginalUrl;

    DirectoryInfo dir = CacheFile.Directory;

    CreateDirectoryChain(dir);

    }

    public override void Write(byte[] buffer, int offset, int count)

    {

    try

    {

    stream.Write(buffer, offset, count); string ContentBlock = Encoding.GetEncoding(1251).GetString(buffer);

     

    Content += ContentBlock;

    }

    catch (Exception ex)

    {

    Log("Write: " + ex.ToString());

    }

    }

    public override void Close()

    {

    stream.Close();

    if (Content.Contains("<!--siteerror-->")) return;

    if (Content != "")

    Content += "<!--cache_url='" +

    OriginalUrl.Replace("&", "&amp;").Replace("<", "&lt;")

    .Replace(">", "&gt;").Replace("%", "&percent;")

    .Replace("?cacheupdate","").Replace("&cacheupdate","").Replace("cacheupdate","") + "' date='" + DateTime.Now.ToString() + "'-->";

    try

    {

    if (!CacheFile.Exists || CacheFile.LastWriteTime <= this.CacheFileLastModifiedData)

    {

    using (StreamWriter sw = new StreamWriter(CacheFile.FullName, false, Encoding.GetEncoding(1251)))

    {

    sw.Write(Content);

    }

    }

    }

    catch { }

    }

    public void CreateDirectoryChain(DirectoryInfo dir)

    {

    if (!dir.Exists) dir.Create();

    }

    #region Filter overridespublic override void Flush()

    {

    stream.Flush();

    }

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

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

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

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

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

    public override long Seek(long offset, SeekOrigin origin) { return stream.Seek(offset, origin); } public override void SetLength(long length) { stream.SetLength(length); }

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

    #endregion

    }

    }

  • 11-12-2009, 7:34 AM In reply to

    Re: My Cache HttpModule and Memory Leaks

    wow, looks like a static page cache module is cooking here... The code isn't quite as clean as it might be. Would you be able to post here the requirements for this module - what is it supposed to do, exactly ?

  • 11-12-2009, 8:35 AM In reply to

    • Serge2k
    • Not Ranked
    • Joined on 07-02-2009, 8:46 AM
    • Posts 6

    Re: My Cache HttpModule and Memory Leaks

    1) when a client requests the page my ISAPI module receives the request

    2) ISAPI module reads the static cache config file (xml) and finds the node that corresponds to the current requested url (if the node is not found the default value is taken)

    3) From the config node i get the cache life time

    4) ISAPI module checkes if a cached file exists. If yes, it looks the last modified date of this file adds cache life time to this value and compares the result with DateTime.Now

    5) If cache file is still valid then ISAPI module reads it, writes inner text to the response and closes the response to prevent executing of the page itself

    6) If cache file doesn't exist or is not valid anymore then ISAPI module attaches the response filter and lets asp.net to execute the page. Then saves the response to the cache file. Smth like this... It works fine.

Page 1 of 1 (3 items)
Microsoft Communities