+1-888-365-2779
Try Now
More in this section

Forums / Bugs & Issues / Sitefinity performance, session state & library resources

Sitefinity performance, session state & library resources

4 posts, 0 answered
  1. Matt
    Matt avatar
    20 posts
    Registered:
    17 Oct 2008
    13 Nov 2008
    Link to this post

    Hi,
    I've been doing some performance testing on SiteFinity in a web farm.
    I have 'InMemory' caching turned on, with a 'InDatabase' cache dependancy.

    Regardless of the InMemory cache there is still quite a bit of database traffic for a page that has lots of library resources. The amount of traffic for the library resources is a little unexpected, am I missing a trick in the caching of these ? (I'd have thought that the in memory cache would keep a cache of the library content id's and the modified dates, and use the etag or similar to send a 304 response where possible.

    Of most concern to our DBAs though is the extra writes to the session state DB required for each resource, since each library resource is now handled by asp.net, so if we're loading a page that contains 20 library images, that means 20 extra writes to the session state database each time that page loads (to update the session expiry time). So my main question is really is there a Sessionless library resource handler, or a way to stop the existing handler from loading session state at all?

    thanks in advance

  2. Vlad
    Vlad avatar
    498 posts
    Registered:
    15 Jul 2016
    19 Nov 2008
    Link to this post
    Hi Matt,

    You are not missing anything, the server caching is not implemented for Library resources in Sitefinity 3.5. Fortunately, it is in progress and will be included in the release.

    For the time being, you can use the following solution:
    You should create a custom HttpHandler inheriting from our Telerik.Cms.Engine.ContentHttpHandler and implement an HttpModule to process the cached library resources:
    using System; 
    using System.Web; 
    using Telerik.Caching; 
    using Telerik.Cms.Engine; 
    using Telerik.Cms.Web; 
     
    // Override the default ContentHttpHandler to implement caching 
    public class CachingContentHttpHandler : ContentHttpHandler 
        protected override void ProcessContentItem(IContent content) 
        { 
            base.ProcessContentItem(content); 
     
            // Insert the content item into the cache 
            LibraryCachingHelper.AddToCache( 
                HttpContext.Current.Request.RawUrl,   
                new CachedLibraryItem((byte[])content.Content, content.MimeType)); 
        } 
     
    // Handles retrieving the library item from the cache 
    public class CachingContentHttpModule : IHttpModule 
        public void Init(HttpApplication context) 
        { 
            context.ResolveRequestCache += new EventHandler(context_ResolveRequestCache); 
        } 
     
        void context_ResolveRequestCache(object sender, EventArgs e) 
        { 
            HttpContext context = HttpContext.Current; 
            CmsHttpRequest cmsRequest = CmsHttpRequest.Current; 
     
            if (cmsRequest != null 
                && cmsRequest.LongExtension == ".sflb.ashx"
            { 
                CachedLibraryItem item = LibraryCachingHelper.GetFromCache(context.Request.RawUrl); 
                if (item != null
                { 
                    ((HttpApplication)sender).Response.Buffer = true
                    ((HttpApplication)sender).Response.ContentType = item.MimeType; 
                    ((HttpApplication)sender).Response.BinaryWrite(item.Data); 
                    ((HttpApplication)sender).CompleteRequest(); 
                } 
            } 
        } 
     
        public void Dispose() 
        { 
        } 
     
        private CachingManager cachingManager; 
     
    public class LibraryCachingHelper 
        static LibraryCachingHelper() 
        {  
            cachingManager = new CachingManager("memoryCache"); 
        } 
     
        public static void AddToCache(string url, CachedLibraryItem item) 
        { 
            string key = "sflib_" + url; 
            cachingManager.Insert(key, item); 
        } 
     
        public static CachedLibraryItem GetFromCache(string url) 
        { 
            string key = "sflib_" + url; 
            return (CachedLibraryItem)cachingManager.Get(key); 
        } 
     
        private static CachingManager cachingManager; 
     
    public class CachedLibraryItem 
        public CachedLibraryItem(byte[] data, string mimeType) 
        { 
            this.data = data; 
            this.mimeType = mimeType; 
        } 
     
        public byte[] Data 
        { 
            get 
            { 
                return this.data; 
            } 
        } 
     
        public string MimeType 
        { 
            get 
            { 
                return this.mimeType; 
            } 
        } 
     
        private string mimeType; 
        private byte[] data; 

    Please bare in mind that this is just a sample, and most probably not all details are considered. The full implementation will be included in the next release. However, if you are interested, you can use the example as a starting point for your custom solution.


    Best wishes,
    Vlad
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  3. Matt
    Matt avatar
    20 posts
    Registered:
    17 Oct 2008
    19 Nov 2008
    Link to this post

    Thanks for the detailed response, glad to hear this will be in the next version!
    since ResolveRequestCache is fired before AquireRequestState this should certainly address the extra session expiry hits!

    It might be useful if we can set the cache-control headers for library resources, so we can leverage client caching. Presumably then we could use an approach like this...

    void context_ResolveRequestCache(object sender, EventArgs e)        
    {        
        HttpContext context = HttpContext.Current;        
        CmsHttpRequest cmsRequest = CmsHttpRequest.Current;        
           
        if (cmsRequest != null && cmsRequest.LongExtension == ".sflb.ashx")        
        {        
            CachedLibraryItem item = LibraryCachingHelper.GetFromCache(context.Request.RawUrl);        
                    
            if (item != null)        
            {        
                string etag = item.ContentVersionID.ToString();        
                if (context.Request.Headers["If-None-Match"] == etag)        
                {        
                    //send a 'not modified' response        
                    ((HttpApplication)sender).Response.StatusCode = 304;  
                    ((HttpApplication)sender).CompleteRequest();        
                }        
                else       
                {        
                    //set the etag to the content version guid        
                    ((HttpApplication)sender).Response.Cache.SetETag(etag);        
                    //configure the browser caching..        
                    ((HttpApplication)sender).Response.CacheControl = "Public";        
                    ((HttpApplication)sender).Response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate");        
                    ((HttpApplication)sender).Response.Cache.SetMaxAge(new TimeSpan(0, 0, item.MaxAge));        
           
                    ((HttpApplication)sender).Response.Buffer = true;        
                    ((HttpApplication)sender).Response.ContentType = item.MimeType;        
                    ((HttpApplication)sender).Response.BinaryWrite(item.Data);        
                    ((HttpApplication)sender).CompleteRequest();        
                }        
            }        
        }        
    }      

     

    thanks
    Matt

  4. Vlad
    Vlad avatar
    498 posts
    Registered:
    15 Jul 2016
    21 Nov 2008
    Link to this post
    Hello Matt,

    Thank you for the note. Yes, we will consider such kind of customization in this implementation in the next release.

    Kind regards,
    Vlad
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Register for webinar
4 posts, 0 answered