Caching of pages on URL path

At the moment we are building up a Epi CMS instance which hosts several sites.
Our content tree is build up in the following way (numbers representing the ID's):

Root (1)
    |_ www.site1.com (2)
        |_ www.site1.com/Contact (3)
        |_ etc.
    |_ www.site2.com (4)
        |_ www.site2.com/Contact (5)
        |_ etc.
    |_ www.site3.com (6)
        |_ www.site3.com/Contact (7)
        |_ etc.
      
Custom Url rewriting (inherited from the FriendlyUrlRewriteProvider) is used to map to the correct branch in the content tree. Our problem is the following:

If, after starting the website, the contact page for site1 is loaded (www.site1.com/Contact), the node with ID 3 is loaded correctly.
If afterwards the contact page for site2 is loaded (www.site2.com/Contact), the node with ID 3 is loaded, which is incorrect. It should be node 5.
After refreshing the page (hitting F5 or Ctrl+F5) on www.site2.com/Contact the proper node/page is loaded (the page with ID 5).

We think the issue has to do with caching of pages in the FriendlyUrlRewriteProvider. We believe the caching is done by using the Path of the URL as the Key. That could explain why both /Contact pages are interfering.
Can someone confirm our suspicion? And if so, can we work around this problem? Is it, for example, possible to change the caching so that the host/domain is included in the caching key?

Thanks in advance!

Jasper

Mar 27, 2012 10:39
  • Hi,

    Are you overriding TryConvertToInternal?

    Why are you using a custom url rewriter for this? You could set up the pages as real startpages, see http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-60/Enterprise---Configuration/.

    Mar 27, 2012 13:23
  • Thanks for your response!

    The main reason we chose custom url rewriting was that the user has to be able to create new subsites from code. We have created code to generate a new content branch for the site and add the URL to a list which is read by our custom URLRewrite provider.

    Setting pages up as start-pages needs to have nodes added to the EPiServer.config. We thought it was risky to do that in code. Also, the website has to be restarted after adding new website startpage(s) to the config.

    Mar 27, 2012 14:42
  • Ok.

    The (output) cache is varied by parameters, like id and epslanguage, not the path. You can override this in global.asax.

    /// <summary>
    /// Get key to vary cached items by. Overrides EPi's way. Needs values in all settings elements, for example:
    /// httpCacheExpiration="0:1:0"
    /// httpCacheability="Public"
    /// httpCacheVaryByCustom="custom"
    /// httpCacheVaryByParams="needs-a-value-but-not-used"
    /// </summary>
    /// <param name="context">The current request's context.</param>
    /// <param name="custom">The string from configuration setting httpCacheVaryByCustom.</param>
    /// <returns>The raw URL of the page requested.</returns>
    public override string GetVaryByCustomString(HttpContext context, string custom)
    {
        return context.Request.RawUrl;
    }

    Not sure this is the problem though.  You can turn it off by setting httpCacheExpiration to 0:0:0 in episerver.config in the site node.

    The rewritten url in your rewriter is cached too, try debug it and see if the rewritten url is translated to the correct page id.

    Mar 27, 2012 14:49
  • Yes we tried overriding GetVaryByCustomString, but found it is only called when output caching is enabled. We have output cached disabled in our project.

     

    If i look in the code of the FriendlyURLRewriteProvider:

     

    private bool ResolveUrlAndCache(UrlBuilder url, FriendlyUrlRewriteProvider.LanguageApiMode apiMode, ref object internalObject, out LanguageBranch languageBranch)
    {
        languageBranch = null;
        string text = "EPiServerFriendlyUrl:" + url.Path;
        object obj = CacheManager.Get(text);
        if (obj != null)
        {
            return obj != FriendlyUrlRewriteProvider._noHit && this.UpdateCachedItem(url, obj, ref internalObject, out languageBranch);
        }
        if (this.ConvertToInternalFacade(url, apiMode, ref internalObject, out languageBranch))
        {
            this.AddToCache(url, text, ref internalObject);
            return true;
        }
        this.StoreInCache(text, FriendlyUrlRewriteProvider._noHit);
        return false;
    }

     

    It looks like the object is retrieved from the cache only on the Path of the url. So now i wonder whether the setup of different startnodes will solve the problem.

    Edited, Mar 27, 2012 15:46
  • Override the TryConvertToInternal()-method, then you're bypassing the built-in cache. Please see my blog post http://www.dodavinkeln.se/post/2012/03/15/Url-rewriter-for-a-blog.aspx

    Mar 27, 2012 15:52
  • Okay thanks, we will try that. I'll come back to tell whether we were able to fix the problem.

    (sorry you already mentioned overriding TryConvertToInternal in your first reply, but i overread it)

    Mar 27, 2012 16:07
  • We've fixed the problem. Unfortunately we use EPi 6.0 on this project, and that version lacks the TryConvertToInternal()-method. But you pointed us in the right direction.

    We've now overridden the ConvertToInternal method, and reversed-engineered the code from the EPiServer assembly using ILspy. We changed the way the cache key is built up. We changed:

                            string key = "EPiServerFriendlyUrl:" + url.Path;

     To:

                            string key = String.Format("EPiServerFriendlyUrl:{0}{1}", url.Host, url.Path);

     

    It seems to work fine now.

    Thanks for the support.

    Mar 29, 2012 12:20
  • Glad I could help you in the right direction. ConvertToInternal() is the equivalent to TryConvertToInternal() in EPi6.

    Mar 29, 2012 13:24
First   1   Last