Friday, April 17, 2015

CQWP, PictureLibrary and Blobcache

ContentByQueryWebPart is a very usable ‘tool’ to display all types of SharePoint data in a page. Listdata, document libraries and also picture library. But be aware that CQWP has some strange default behaviour wrt picture library. CQWP by default displays the preview images, instead of the actual images.
This also has several performance ramifications:
  1. On server side: actual images can be cached in blobcache, but preview images and also thumbnails are by SharePoint design not cached in blobcache. The reasoning is that blobcache is for content that is multiple times (often) retrieved, while preview images are typically only of interest for content manager upon functional management of the picture library contents. As result, each request for a preview image means that SharePoint needs to retrieve it from the content database.
  2. On client, network + server side: browser cache can be applied to avoid the browser over and over requesting same image. But the browser then still needs to query the server whether the cached resource is unmodified at the server (response 304). For images / static resources that do not change (often), even this request can be avoided: minimizing request/response handling between client (browser), server, and the network transfer. Browsers support this via ‘max-age’ setting. SharePoint supports this ‘max-age’ setting for SharePoint content, via… Blobcache. For SharePoint content retrieved outside blobcache, as thus preview images, the max-age value is not set in the http response. As result, the browser will query the remote SharePoint server whether the image is unmodified, and the server responds with '304 NotModified'. And this can end-up in some noticeable latency, dependent on how busy the SharePoint server is:
Solution is to modify the CQWP configuration to retrieve and display the actual image. This comprises of 2 parts:
  1. In the ItemStyle.xsl, change the rendering specification to display ‘EncodedAbsUrl’ iso ‘ImageUrl’;
  1. And you need to modify the ‘CommonViewFields’ specification of CQWP instance, to also include ‘EncodedAbsUrl’.

Friday, April 10, 2015

ScriptEditor reloads script-links

On the homepage of our SharePoint 2013 intranet we allow employees to install apps. One of them is for internal company ‘fun and facts’: Did you know? The global design of this app is a SharePoint list with the ‘fun and facts’, and jQuery script to get selected listitems via listdata.svc and bind the returned JSON data to html elements. The jQuery script is deployed to the Style Library in the site collection, and the link to this script file is provisioned to the page via a ScriptEditor webpart:
<div id="DW-DYK-Container"></div> <script type="text/javascript" src="/Style Library/Scripts/DidYouKnow.js" ></script>
For performance tuning I regularly monitor via Fiddler the http requests that the browser sends for a page visit. With the modern web applications constructed partly as html+css+javascript, the number of http requests can grow to a larger set as one is aware. In the Fiddler trace, I spotted the browser request for the script file ‘/Style Library/Scripts/DidYouKnow.js’, on which SharePoint responds with ‘304 NonModified. But to my surprise I also noticed a second Http Get request for the same script file, and this url is made unique to force renewed retrieval from the server.
I analyzed what causes this second request for the script file. My finding is that it is caused by the ScriptEditor class. The above ScriptEditor content is rendered to the following html:
SharePoint 2013 includes Embed Code handling that detects ‘orphan’ client script code in the page html, and does some magic with that. Part of that magic apparently is to force the (re)loading of script-links that are within the ‘ms-rte-embedcode’ div-element, via an equivalent of jQuery’s getScript() method (that also adds an unique part to the url to force script file reload from the server). However, from performance and in particular latency perspective, I dislike this behaviour: I do not want the extra request and certainly not the everytime renewed retrieval of the script-file of which I know it remains stable. So I came up with an approach to break out of the ‘magic’ of ScriptEditor: move the ‘script’ element outside of the ‘ms-rte-embedcode’ div-elements:
<div id="DW-DYK-Container"></div> <script language='javascript' type='text/javascript'> var head = document.getElementsByTagName('head').item(0); var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', '/Style Library/Scripts/DidYouKnow.js'); head.appendChild(script); </script>
I admit: the code is more complex as the initial one. But the result is what I want: no more duplicate and repetitive forced retrieval of the script file.

Friday, April 3, 2015

Max-age cache-control setting for SharePoint content

Browser-cache is often utilized to improve the performance and in particular latency of webapplications. Default, the browser will still go back to the remote web server on each request for cached resources to ask whether it can be reused from cache (HTTP 304), or has changed on the server since retrieved. For resources that rarely or never change (e.g. a specific version of jQuery library), it is beneficial to avoid the browser even send out the ‘has it changed’ requests. The http protocol supports this via ‘max-age’ cache-control header.
SharePoint supports the ‘max-age’ header setting. Application pages retrieved from the file system (12/14/15 hive) follow the IIS Response Headers setting. However, the IIS setting is not applied to content that is retrieved from SharePoint lists and libraries. If you also want to have the ‘max-age’ setting in the HTTP response for these items, you need to enable the SharePoint blobcache and specify ‘max-age’ value in the web.config: <BlobCache location="C:\blobCache" path="\.(gif|jpg|png|css|js)$" maxSize="10" max-age="86400" enabled="true"/>
Something to be aware of is that SharePoint only applies the blobcache for published items. The version of a file stored in a SharePoint library (e.g. Style Library) that has not been published, will not be cached in the blobcache. The valid reasoning here is that caching is contra-productive, as non-published SharePoint content typically is accessible to only a few persons instead of a large(r) audience. A consequence of this is that the ‘max-age’ cache-control setting will not be set in the http response for the retrieved item if the logged-on user has SharePoint permission to see the non-published version:
Publish the version, and the 'max-age' cache-control setting is included in the http response.