[VERY URGENT] - Sitefinity Cache Configuration

Posted by Community Admin on 04-Aug-2018 11:55

[VERY URGENT] - Sitefinity Cache Configuration

All Replies

Posted by Community Admin on 24-Feb-2012 00:00

Hi,

We have performance problems on our website (4.3.1885) in all of our environments. It may be partly be due to our cache configuration on Sitefinity, so we are in need of some explanations.

In backend "Administration > Settings > Advanced > System > Output Cache Settings > Output Cache Profiles" we create our own caching like this :

<outputCacheSettings>
   <profiles>
         <add enabled="True" duration="2700" slidingExpiration="False" maxSize="500" name="Insite Caching" />
   </profiles>
</outputCacheSettings>

But it seems that cache doesn't last 45 minutes, it expires before that. On top of that, it seems to be client specific: the page cache generated by one person doesn't benefit other persons, everyone generates their own page cache. On a given computer, the cache is not even shared between different browsers. Yet, from what we understand, this cache shouldn't be a client cache. Maybe we are misunderstanding something?
Under "Output Cache Settings", there is "Output Cache Profiles" and "Client Cache Profiles". We expected the "Ouput Cache Profiles" to be server caches. Are they not?

We also see differences between browsers: we need two page accesses on IE8 to generate the page cache, but only one on Firefox.

In the configuration settings at the same place, we can reconfigure CacheManagers, but we don't know what to do and if it could help. Is this worth exploring this? If so, what could we do?

Thanks in advance for your reactivity, as this problem is critical for us right now.

Regards,
Nicolas

Posted by Community Admin on 27-Feb-2012 00:00

Hi,

Could a Sitefinity admin answer this question, or post a link to the documentation explaining everything we want to know about the cache?

Thanks.

Posted by Community Admin on 27-Feb-2012 00:00

Hello,

In general Sitefinity implements two types of caching - OutputCache through its Output cache settings and DataCache through its OpenAccess implementation. While the data cache is turned on my default and cannot be controlled directly by Sitefinity, OutputCache is available for fine tuning by user requirements.

In backend "Administration > Settings > Advanced > System > Output Cache Settings > Output Cache Profiles" we create our own caching like this :

<outputCacheSettings>
   <profiles>
         <add enabled="True" duration="2700" slidingExpiration="False" maxSize="500" name="Insite Caching" />
   </profiles>
</outputCacheSettings>

But it seems that cache doesn't last 45 minutes, it expires before that.
Can you please make sure that this is the Default Output Cache Profile set for the entire site?

On top of that, it seems to be client specific: the page cache generated by one person doesn't benefit other persons, everyone generates their own page cache. On a given computer, the cache is not even shared between different browsers.

By default Sitefinity sets the output cache to vary by user agents. This is done so, because different browsers have different capabilities, and sometimes you will need to put browser specific HTML and CSS to resolve frontend issues. If you do not have such issues in your project you can manually set the caching headers by inhering from the RouteHandler which serves Sitefinity pages. Bellow are the steps that you need to do:

1) Create a class which inherits from PageRouteHandler, and override the InitOutputCache method. This will give you control over the caching headers:
using Telerik.Microsoft.Practices.Unity;
using Telerik.Sitefinity.Abstractions;
using Telerik.Sitefinity.Web;
  
  
namespace SitefinityWebApp
    public class CustomPageRouteHandler: PageRouteHandler
    
        protected override void InitOutputCache(System.Web.Routing.RequestContext requestContext, PageSiteNode siteNode)
        
            base.InitOutputCache(requestContext, siteNode);
            var cache = requestContext.HttpContext.Response.Cache;
             cache.VaryByHeaders.UserAgent = true;
        
  
        public static void RegisterType()
        
            ObjectFactory.Container.RegisterType<PageRouteHandler, CustomPageRouteHandler>();
        
    

2) Create a Global Application class (Global.asax). There you will call the RegisterType method of the custom route handler to substitute the built in one with the custom one:
protected void Application_Start(object sender, EventArgs e)
    Bootstrapper.Initialized += new EventHandler<Telerik.Sitefinity.Data.ExecutedEventArgs>(Bootstrapper_Initialized);
  
void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs e)
    if (e.CommandName == "RegisterRoutes")
    
        CustomPageRouteHandler.RegisterType();
    

3) Compile your project and run it

IN addition, please check out the tips for optimizing performance: Tips for optimizing performance. We recommend that you verify that you have enabled caching throughout the site as well as make sure you have a machinekey set in the web.config and enabled static content expiration:
staticContent>
  <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
</staticContent>
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true" />

if any problems persist  I'd recommend you contact us through the support ticketing system in order to benefit from the guaranteed response time we're offering there.

Greetings,
Boyan Barnev
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 28-Feb-2012 00:00

Hi,
Thanks for your answer. We are testing your solution.

I have a question about it, when we set clienCache MaxAge in web.config it's an  override of OutputCache original MaxAge value ?

Regards,
Nicolas

Posted by Community Admin on 28-Feb-2012 00:00

Hi,

Thanks for your answer, Boyan, much appreciated.

It's surprising that a user agent-based cache is the default, and that there is no simple flag to revert to a classic cache. By the way, as you know, many things can make the user agent vary (whether .NET 4.0 is installed, etc...), and in our company, IE8 users do not all have the same UA.

Anyway, we do not serve browser-specific content. Does Sitefinity do it, with its components (like, say, the standard navigation menu), or does it serve the same HTML to everyone?

Thanks.

Posted by Community Admin on 29-Feb-2012 00:00

Hi,

Follow-up: we created a class derived from PageRouteHandler, as advised, in order to control the way caching works. However, we're encountering an unexpected problem: pages set to "No Caching" are now cached. I guess that in the code sample you showed, we were supposed to add a check for whether the page cache is enabled or not.

Edit: our method now looks like this:

protected override void InitOutputCache(System.Web.Routing.RequestContext requestContext, PageSiteNode siteNode)
    base.InitOutputCache(requestContext, siteNode);
 
    var config = Config.Get<SystemConfig>();
    if (config.CacheSettings.EnableOutputCache)
    
        var cacheProfile = siteNode.OutputCacheProfile;
        if (cacheProfile.IsNullOrEmpty())
        
            cacheProfile = config.CacheSettings.DefaultProfile;
        
 
        OutputCacheProfileElement profile;
        if (!config.CacheSettings.Profiles.TryGetValue(cacheProfile, out profile))
        
            throw new ArgumentException("Invalid output cache profile specified: \"0\".".Arrange(cacheProfile));
        
 
        if (profile.Enabled)
        
            var cache = requestContext.HttpContext.Response.Cache;
            cache.VaryByHeaders.UserAgent = false;
            cache.SetMaxAge(new TimeSpan(0, 0, 172800));
        
    

Posted by Community Admin on 02-Mar-2012 00:00

Hello Thomas,

Can you please try adding an else clause where you'll set explicitly the Cacheability to None. Like this:

var config = Config.Get<SystemConfig>();
            if (config.CacheSettings.EnableOutputCache)
            
                var cacheProfile = siteNode.OutputCacheProfile;
                if (cacheProfile.IsNullOrEmpty())
                
                    cacheProfile = config.CacheSettings.DefaultProfile;
                
 
                OutputCacheProfileElement profile;
                if (!config.CacheSettings.Profiles.TryGetValue(cacheProfile, out profile))
                
                    throw new ArgumentException("Invalid output cache profile specified: \"0\".".Arrange(cacheProfile));
                
 
                if (profile.Enabled)
                
                    var cache = requestContext.HttpContext.Response.Cache;
                    cache.VaryByHeaders.UserAgent = false;
                    cache.SetMaxAge(new TimeSpan(0, 0, 172800));
                
                       
            else
                requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);


Greetings,
Boyan Barnev
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 02-Mar-2012 00:00

Hi Boyan,

Thanks for the info.
By the way, our updated method already worked for our case. I guess your update helps if we disable the cache for the whole site, as opposed to disabling the cache for certain pages, so we'll add this bit of code.

I was wondering whether we should also add the same no cache instruction in a else for the profile.Enabled. That is to say:

if (profile.Enabled)
    var cache = requestContext.HttpContext.Response.Cache;
    cache.VaryByHeaders.UserAgent = false;
    cache.SetMaxAge(new TimeSpan(0, 0, 172800));
else
    requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);

What do you think?

Posted by Community Admin on 06-Mar-2012 00:00

Hello,

Yes that should do, or you could just say:

if (config.CacheSettings.EnableOutputCache)
           
               .
               .
               .
 
               if (!profile.Enabled)
                   return;
 
             .
             .
             .
 
               //if output cache is enabled set flag to add cache dependencies
               requestContext.HttpContext.Items[PageRouteHandler.AddCacheDependencies] = true;
           
           else
               requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);


Greetings,
Boyan Barnev
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 06-Mar-2012 00:00

Hi Boyan,

So I don't need to call Cache.SetCacheability(HttpCacheability.NoCache); explicitly there? Okay.
I added the AddCacheDependencies instruction, although I'm not sure what it does exactly, and I can't find any documentation for it.

This is our method now:

protected override void InitOutputCache(System.Web.Routing.RequestContext requestContext, PageSiteNode siteNode)
    base.InitOutputCache(requestContext, siteNode);
 
    var config = Config.Get<SystemConfig>();
    if (!config.CacheSettings.EnableOutputCache)
    
        requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    
    else
    
        var cacheProfile = siteNode.OutputCacheProfile;
        if (cacheProfile.IsNullOrEmpty())
        
            cacheProfile = config.CacheSettings.DefaultProfile;
        
 
        OutputCacheProfileElement profile;
        if (!config.CacheSettings.Profiles.TryGetValue(cacheProfile, out profile))
        
            throw new ArgumentException("Invalid output cache profile specified: \"0\".".Arrange(cacheProfile));
        
 
        if (profile.Enabled)
        
            var cache = requestContext.HttpContext.Response.Cache;
            cache.VaryByHeaders.UserAgent = false;
            cache.SetMaxAge(new TimeSpan(0, 0, 172800));
            requestContext.HttpContext.Items[PageRouteHandler.AddCacheDependencies] = true;
        
    

Posted by Community Admin on 09-Mar-2012 00:00

Hello,

By default we add dependency on a page site node cache key, so when page site node is invalidated (e.g. Publish) the output cache key of the page should be refreshed.

All the best,
Boyan Barnev
the Telerik team

Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 22-Mar-2012 00:00

Hi Boyan,

I just noticed something else that I do not understand: pages set no "No Caching" are still cached (whether we override the InitOutputCache method or not). If I modify the content of a page set to No Caching, I cannot see the changes on other servers where the site is deployed. I can only see the changes on the server from which the modification has been done (until the site is restarted on the other servers). Although I haven't configured load balancing, so other servers aren't informed the page has been modified, shouldn't I see the changes on the page considering both the data and page caches are disabled?

I also want to add that we have not changed the "No Caching" profile settings at all, it's the default, unaltered one.

Posted by Community Admin on 25-Jun-2012 00:00

We are seeing the same issue: with two separate SF 4.3 instances that share a database, content changes made on one instance are not visible on the other. This is even with global output caching disabled, data caching set to "False", and page-level cache set to "No Caching".

What are we missing? Why does Sitefinity not bypass the cache if the page is set to no caching?

This is a very urgent issue for us.

Regards,
John Gassman

Posted by Community Admin on 15-Aug-2012 00:00

John, did you ever find a solution for this? Running into the same problem for us.

Posted by Community Admin on 15-Aug-2012 00:00

Glenn: The only working solution was to configure the servers as if they were in the load-balanced configuration (following Sitefinity's load-balanced setup instructions). Basically, we had to enter the IP address(es) of the each other server into each servers SF config to allow each SF instance to communicate with the others. You also need to be sure to manually set the machineKey in web.config to the same value in all SF instances.

There is some communication sent to all configured servers to tell them to invalidate their content cache when a content change is made.

No manner of messing with cache settings worked for us.

Posted by Community Admin on 15-Aug-2012 00:00

Ahh okay, that is what I was afraid of. 

So did you have to run the sites from a file share? Or can they each have their own copy of Sitefinity and just setup the configuration for them to talk to each other?

We have three web servers (2 production and 1 for editing) all talking to the same db. 

Thanks for your quick response....

Posted by Community Admin on 15-Aug-2012 00:00

Hey Glenn,

Our client did *not* go the file share route. Only the machineKey + IP address config. Personally, I think the file share is a very un-enterprise-y solution, and can't see many IT folks going that route.

- John G

Posted by Community Admin on 10-Jul-2013 00:00

Hi all,

Just a quick follow-up to this thread,as it seems to be getting hits every now and then.

The initially provided example wouldn't work due to the fact that the .NET implementation for the VaryByHeaders.UserAgent would not allow us to set it to false directly (techincally it would but in the background, if you check the System.Web.HttpCacheVaryByHeaders implementation you'd notice that the setter of all headers has this line:

if (!value)
                
                    return;
                
 so we'll have to use reflection to address our need for setting the header to false. Please find an updated sample below:

using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Web.Routing;
using Telerik.Microsoft.Practices.Unity;
using Telerik.Sitefinity.Abstractions;
using Telerik.Sitefinity.Web;
 
namespace SitefinityWebApp
    public class PRHCustom : Telerik.Sitefinity.Web.PageRouteHandler
    
        /*NOTE! - for this sample we're reading the value of the of the VaryByHeaders.UserAgent form the web.config <appSettings> section           
             * To specify whether you want the same chached version of the page to be served on all browsers (VaryByHeaders.UserAgent=false;)
             *  please add an entry to your web.config <appSettigns> similar to:
             *
                <appSettings>
                 <add key="VaryByHeaders_UserAgent" value="false"/>
             *
             * where value can be true (default Sitefintiy chache behavior) or false
             */
 
        protected override void InitOutputCache(RequestContext requestContext, PageSiteNode siteNode)
        
            base.InitOutputCache(requestContext, siteNode);
 
            if (!(ConfigurationManager.AppSettings["VaryByHeaders_UserAgent"]).IsNullOrEmpty())
            
                if (!Boolean.Parse(ConfigurationManager.AppSettings["VaryByHeaders_UserAgent"].ToString()) && requestContext.HttpContext.Response.Cache.VaryByHeaders != null && requestContext.HttpContext.Response.Cache.VaryByHeaders.UserAgent)
                
                    //Need to use reflection as .NET does not allow for setting false value once we've set it to true
                    var headers = requestContext.HttpContext.Response.Cache.VaryByHeaders;
                    var headersCollection = (NameObjectCollectionBase)headers.GetType().GetField("_headers", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(headers);
                    var method = headersCollection.GetType().GetMethod("BaseRemove", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                    method.Invoke(headersCollection, new string[] "User-Agent" );
                
            
        
 
        /// <summary>
        /// This method has to be invoked in your Global.asax (subscribe to Bootstrapper_Initialized and verify inside your Bootstrapper_Initialized event handler that e.CommandName == "Bootstrapped"),
        /// as it would effectively carry out replacing the default PageRouteHandler with the custom one through the ObjectFactory
        /// </summary>
        public static void RegisterType()
        
            ObjectFactory.Container.RegisterType<Telerik.Sitefinity.Web.PageRouteHandler, PRHCustom>();
        
    



Regards,
Boyan Barnev
Telerik
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 06-Sep-2013 00:00

Boyan,

I have tried your latest example and it appears to not cache at all. When I comment out the registration of the handler I get caching on a per user-agent basis. But if I run with that route it hits the database for every visit from the same machine/browser.

Any idea what I may be doing wrong?

Thanks,
Ryan

This thread is closed