Sitecore vary output cache by context item and datasource

Sitecore’s output cache is an excellent solution to improve the performance of a Sitecore solution. The output cache can be configured to be different for a variety of criteria as explained by John West in this post.

The most common option is the VaryByData option. I don’t think this option is documented very well, but it will vary the cache based on the datasource if it is set. The context item will be used instead if no datasource is set.

VaryByData will vary the cache based on Datasource if set, otherwise it will use the context item.

This will work well in most cases, but there are valid scenarios where the cache should vary based on the datasource and the context item. This can be avoided by adding below pipeline. This will use Sitecore’s logic to determine the cachekey, but will add the item path. The if statement can be adjusted depending on the need. Examples include setting it to the ID of the rendering that requires it or checking if rendering’s Datasource property is set if this is required for all renderings that have a datasource.

public class GenerateCacheKeyCustomized : GenerateCacheKey
{
    protected override string GenerateKey(Rendering rendering, RenderRenderingArgs args)
    {
        var cacheKey = base.GenerateKey(rendering, args);

        if (rendering.RenderingItemPath == "<your ID>")
        {
            cacheKey += string.Format("_{0}", Sitecore.Context.Item.Paths.Path);
        }

        return cacheKey;
    }
}
Advertisement

How to leverage Sitecore Media Request Protection in javascript/client side code

Sitecore Media Request Protection is an important feature which protects a Sitecore instance from an image resize attack. It protects Sitecore image scaling parameters by ensuring that only server generated requests are processed. This creates issues if you have any client side code that needs to leverage image scaling. For example what if you have some client side databinding that needs to show images in lower dimensions? This blog discussed 2 techniques that can be used to get around this issue while still leaving Sitecore protected from a resize attack.

1. Protect each image server side when sending image data to client

Most likely the information about the images to display will come from the Sitecore server. Instead of just sending information about the image path also already send the image scaling parameters and call ProtectAssetUrl method as described here This will add the hash value to the path so any javascript code can safely use this image URL

2. Allow known dimensions that will be requested client side

You will know in which dimensions your client side code will request images. This approach will allow all valid images dimension while all other images dimensions will only be allowed when a valid hash is provided.  Media request protection is implemented in the MediaRequest pipeline and can be customized just like almost anything else in Sitecore. Below code will check if an unsafe request is using a  ‘safe’ dimension and if so allow that:

public class CustomMediaRequest : sc.Resources.Media.MediaRequest
{
    protected override bool IsRawUrlSafe
    {
        get
        {
            bool isSafe = base.IsRawUrlSafe;

            if (!isSafe)
            {
                var safeQueryStrings = new List
                    {
                        "mh=123&mw=456",
                        "mh=654&mw=321"
                    };

                foreach (var safeQueryString in safeQueryStrings)
                {
                    if (this.InnerRequest.RawUrl.Contains(safeQueryString))
                    {
                        return true;
                    }
                }
            }

            return isSafe;
        }
    }
}

This pipeline can be included as follows:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <mediaLibrary>
      <requestParser patch:instead="*[@type='Sitecore.Resources.Media.MediaRequest, Sitecore.Kernel']" type="namespace.CustomMediaRequest,  assembly" />
    </mediaLibrary>
  </sitecore>
</configuration>

Conclusion

The first method is the better method as it uses the OOTB functionality to protect image URL’s and does not allow additional image scaling to take place. I find it hard to think of a scenario where this method will not be feasible and will recommend this for any new development. However the MediaRequest feature is still relatively new as it is introduced in Sitecore 7.5. You might need to upgrade a solution from an older version and run into many issues with a limited amount of distinct image dimensions that are requested. In this case it is probably easier and less risky to use approach 2.

Protocol relative URL not working with Sitecore Media Request Protection

Using a protocol relative URL (e.g. “<img src=”//www.mysite.com/~/media/image.png?mh=50” />) is a great way to load a resource from a different domain over HTTP when the page it is referenced on is on HTTP and over HTTPS when it is on a page which is loaded over HTTPS. You want to ensure Media Request Protection is turned on in case you want to do some scaling of the image as in the sample above to protect your Sitecore instance.

In above scenario it is easy to run into issues as the hash generated to protect the image does not handle the protocol relative url properly. Consider below hash values generated by admin page at /sitecore/admin/mediahash.aspx

  1. /~/media/image.png?mh=50 gives hash  07205019C3F1F44438D529F64842DBEE98C0632B
  2. http://www.mysite.com/~/media/image.png?mh=50 results in same hash
  3. https://www.mysite.com/~/media/image.png?mh=50 also results in same hash
  4. //www.mysite.com/~/media/image.png?mh=50 gives a different hash 5A309EF4DC195929BA7EE946A0E66AD6D349712B

I did run in a number of issues because the difference in hash value and decided against using protocol relative URL and instead always load the images over HTTPS which is working well with Media Request Protection. Recent developments also indicate that loading as much as possible over SSL is the better approach see here

Use Azure CDN Custom Origin for items in Sitecore media library

Using a CDN can significantly improve loading times of your site as static resources like images can be retrieved from it. A CDN has many edge servers and will automatically serve the resource from the closest location to the user. Additionally they will decrease the load on the webserver as it does not need to serve the resource to individual users.

Last year Azure announced custom origin support in their CDN. Before that you could only use the CDN from a limited set of Azure services in your Azure subscription like the Cloud Service that hosted your Sitecore environment. I have seen some complicated solutions to have the CDN use Sitecore. This was especially complicated if the cloud service hosted multiple Sitecore instances. Using the CDN is much easier with this new policy. This post will describe the steps involved in setting this up.

The first step is to set up the Azure CDN with custom origin, use the URL of your Sitecore site as the origin URL. This can be done either on the new or classic Azure Portal, see screenshots below:

custom-origin-new-portal
Classic portal:
custom-origin-blog

When the CDN is created it will generate a URL for it, something like http://az123456.vo.msecnd.net/ It is also possible to map a custom domain to this endpoint see here

Now the CDN is ready to use and you can retrieve any media library item, for example if your image has a URL of http://mysitecoresite.com/-/media/images/image.png then you can load it now from http://az123456.vo.msecnd.net/-/media/images/image.png

The CDN is now ready to use however the CDN edge servers will not cache the image but instead return it from the origin which is the Sitecore server. This is because by default Sitecore sets cache-control to private which causes the CDN not to cache it. This has to be changed to public in the Sitecore settings:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <settings>
      <setting name="MediaResponse.Cacheability">
        <patch:attribute name="value">public</patch:attribute>
      </setting>
    </settings>
  </sitecore>
</configuration>

Now static resources will be cached by Azure’s CDN edge servers so site will load faster for your users.

Sitecore WFFM 8.1 incorrectly detects forged request

Sitecore Web Forms For Marketers 8.1 rev.151217 (Update-1) has recently been released, see release notes here As mentioned in the release notes this includes a new feature to prevent forging request.

For some reason I’m seeing valid request (the initial form was served by the Sitecore server and is submitted back to the same server) incorrectly being detected as forged request which causes the form the error. I’m currently working with Sitecore to try to understand why this is happening and understand what the root cause is. I will let you know if i figure out this issue.

Please let me know if anyone else is running into the same issue hopefully it can help troubleshoot this. Also Sitecore can provide a custom DLL which avoids the page crashing in this scenario.

GlassMapper GetRenderingParameters returning null after upgrade

If you have recently upgraded GlassMapper you might run into an issue where GetRenderingParameters returns null. I believe this started occuring in version 4.0.2.10 or 4.0.3.50. I was only experiencing this in WebForms. The issue occurs when you call GetRenderingParameters as described in this article (section “ASP .NET Webforms”).

The good news is that this issue has already been reported so hopefully it will be fixed in the next release. If you really need to upgrade to a version with this issue then you can easily fix this by downloading the code from github here and compiling Glass.Mapper.Sc DLL yourself.

The only code change that is required is to change

var sublayout = _control as Sublayout;

to remove underscore in control to reference the method parameter

var sublayout = control as Sublayout;

On line 40 of GetRenderingParametersInternal in Glass.Mapper.Sc.Web.Ui.GetRenderingParametersInternal see file in Github here

Filter items without language version in Sitecore Item Web API

The Sitecore Item Web API is a great tool to query Sitecore client side and retrieve JSON data which can be shown through a JavaScript library like Angular or Knockout. The Item Web API will return all items that match a query even if there is no version of an item in the current language. This can lead to unnecessarily large HTTP responses which will slow down the page, especially in multilingual sites with many languages with different content per language.

One nice feature of Item Web API is the ability to easily customize it. Below simple pipeline can be added to filter out any item that matches a query but does not have a version in the current language:

using Sitecore.Diagnostics;
using Sitecore.ItemWebApi.Pipelines.Read;
using Sitecore.Web;
using System.Linq;

namespace Jeroen.Pipelines.WebAPI
{
    public class RemoveItemsWithoutLanguageVersion : ReadProcessor
    {
        public override void Process(ReadArgs arguments)
        {
            Assert.ArgumentNotNull(arguments, "arguments");

            if (WebUtil.GetQueryString("language-filter", null) == "1")
            {
                arguments.Scope = arguments.Scope.Where(i => i.Versions.Count > 0).ToArray();
            }
        }
    }
}

I’m only doing this filtering when a query string of language-filter=1 is passed. I add this to every query that needs it. This avoids any conflicts with existing functionality which uses Item Web API like the Sitecore Desktop. Above pipeline is enabled in Sitecore.ItemWebApi.config as follows:

<itemWebApiRead>
   <processor type="Jeroen.Pipelines.WebAPI.RemoveItemsWithoutLanguageVersion, Jeroen.Pipelines" />
 </itemWebApiRead>

Avoid Sitecore performance degradation with SQL Azure

SQL Azure is a great choice for hosting Sitecore’s databases. Out of the box it provides many features like high uptime SLA, performance you can adjust easily based on demand and geo-replication. Since Sitecore 8 you can publish your databases to SQL Azure without any schema changes.

If you are using SQL Azure for a while you might notice that your Sitecore’s performance might go down over time especially at times when the database gets hit hard for example right after an application pool recycle. I initially had many incorrect assumptions regarding the source of these issues, I looked into prefetch cache, additional content, site traffic etc. Eventually i figured out that i had to update statistics and query plans which immediately resolved this issue.

This issue is not specifically related to Sitecore only but can be experienced with other technologies as well. However be sure to update statistics regularly to avoid any unnecessary performance issues in your site.

Sitecore upgrade from 8.0 to 8.1 without xDB

Sitecore recently released version 8.1, even without xDB there are some new exciting features introduced for example the new language fallback features and fully integrated IP Geolocation services. A more detailed list can be found here.

When you do not have xDB enabled and are upgrading from 8.0 to 8.1 then there is one setting that you will need to correctly update otherwise a number of things will most likely break without any clear indication what the root cause is.

In Sitecore 8.0 you had to follow this guide and disable the Analytics.Enabled setting. It is easy to assume that the same would apply to Sitecore 8.1. However in Sitecore 8.1 you’ll have to set CMS only mode by setting xDB.enabled to false in Sitecore.Xdb.config. You can verify xDB is correctly disabled by looking in the Sitecore log for a message like this “1234 17:21:20 INFO xDB is disabled.”

Hopefully this will help someone. Apart form this I found upgrading from 8.0 to 8.1 straightforward.