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

Forums / Developing with Sitefinity / [VERY URGENT] - Sitefinity Cache Configuration

[VERY URGENT] - Sitefinity Cache Configuration

19 posts, 0 answered
  1. Nicolas
    Nicolas avatar
    156 posts
    Registered:
    19 Jan 2011
    24 Feb 2012
    Link to this post
    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
  2. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    27 Feb 2012
    Link to this post
    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.
  3. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    02 Dec 2016
    27 Feb 2012
    Link to this post
    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
  4. Nicolas
    Nicolas avatar
    156 posts
    Registered:
    19 Jan 2011
    28 Feb 2012
    Link to this post
    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
  5. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    28 Feb 2012
    Link to this post
    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.
  6. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    29 Feb 2012
    Link to this post
    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));
            }
        }
    }
  7. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    02 Dec 2016
    02 Mar 2012
    Link to this post
    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
  8. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    02 Mar 2012
    Link to this post
    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?
  9. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    02 Dec 2016
    06 Mar 2012
    Link to this post
    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
  10. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    06 Mar 2012
    Link to this post
    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;
            }
        }
    }
  11. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    02 Dec 2016
    09 Mar 2012
    Link to this post
    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
  12. Thomas
    Thomas avatar
    223 posts
    Registered:
    19 Jan 2011
    22 Mar 2012
    Link to this post
    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.
  13. John
    John avatar
    61 posts
    Registered:
    08 Jun 2012
    25 Jun 2012
    Link to this post
    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
  14. Glenn
    Glenn avatar
    10 posts
    Registered:
    22 Jan 2007
    15 Aug 2012
    Link to this post
    John, did you ever find a solution for this? Running into the same problem for us.
  15. John
    John avatar
    61 posts
    Registered:
    08 Jun 2012
    15 Aug 2012
    Link to this post
    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.
  16. Glenn
    Glenn avatar
    10 posts
    Registered:
    22 Jan 2007
    15 Aug 2012
    Link to this post
    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....
  17. John
    John avatar
    61 posts
    Registered:
    08 Jun 2012
    15 Aug 2012
    Link to this post
    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
  18. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    02 Dec 2016
    10 Jul 2013
    Link to this post
    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
  19. Ryan
    Ryan avatar
    5 posts
    Registered:
    11 May 2013
    06 Sep 2013
    Link to this post
    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
19 posts, 0 answered