Dynamically Generating URLs for Cached Web Resources for Microsoft Dynamics CRM

CRM 2011 supports several methods for accessing web resources.  These includes using the $webresource: directive when referencing web resources from the site map or ribbon, a relative URL, or an absolute URL.  While this allows a web resource to be accessed in virtually any situation, if a scenario arises in which an absolute URL must be used, the benefit and speed of retrieving the cached web resource is lost.  The reason for this has to do with the caching mechanism used by CRM for web resources.  Take the following URL that could be generated by CRM when using the $webresource: directive or when a web resource is included on a CRM form as an example.


Notice the magic number that is highlighted in the example URL.  CRM automatically inserts this token into the URL and the CRM 2011 SDK indicates that this magic number is a GUID value that ensures the latest cached version of the requested web resource is used.  If you use a tool like Fiddler to examine the response returned by the GET request for the web resource, you will notice that it has caching headers that set it to be cached for one year.  If the magic GUID value is removed from the URL so that the URL would resemble an absolute URL to the web resource, the response returned by the GET request for the web resource, depending upon your version of CRM, will be a non cached version or a version that is cached for a short amount time such as 24 hours.

This caching functionality provided by CRM is great, but what if you need to dynamically generate the URL for a large web resource?  It would be preferable to access the cached version, but in order to do that you need the magic GUID value.  Fortunately, the magic GUID value is not magic at all, and not actually a GUID.  The caching token inserted into the URL for the web resource by CRM is merely a timestamp that represents the modified time of the last web resource to be modified.  The timestamp is represented as ticks in UTC time as generated by the .NET Framework.

Now in order to get the URL for a web resource, it is merely necessary to generate this timestamp.  The example function below shows exactly how to generate the timestamp for the caching token using a quick call to the REST service in CRM and a simple conversion from the JavaScript Date object to the timestamp value.

 1: function getWebResourceUrl(webResourceName) {
 3:     var dotNetMillisecondsAt_1970_01_01 = 62135596800000,
 4:         ticksPerMillisecond = 10000,
 5:         lastWebResourceModifiedOn = null,
 6:         webResourceCachingToken = null,
 7:         webResourceUrl = "/WebResources/" + webResourceName;
 9:     // Retrieve the modified date of the last web resource to be modified
 10:     $.ajax({
 11:         async: false,
 12:         beforeSend: function (xhr, settings) {
 13:             xhr.setRequestHeader("Accept", "application/json");
 14:         },
 15:         contentType: "application/json; charset=utf-8",
 16:         datatype: "json",
 17:         global: false,
 18:         success: function (data, textStatus, xhr) {
 20:             // Extract the modified date from the results
 21:             lastWebResourceModifiedOn = +(/\/Date\((\d*)\)\//.exec(data.d.results[0].ModifiedOn)[1]);
 23:             // Convert the JavaScript Date value to the caching token value
 24:             webResourceCachingToken = (lastWebResourceModifiedOn + dotNetMillisecondsAt_1970_01_01) * ticksPerMillisecond;
 25:         },
 26:         type: "GET",
 27:         url: Xrm.Page.context.prependOrgName("/XRMServices/2011/OrganizationData.svc/WebResourceSet()?$select=ModifiedOn&$orderby=ModifiedOn%20desc&$top=1")
 28:     });
 30:     // If we have a caching token value then prepend it to the current URL.
 31:     if (webResourceCachingToken !== null) {
 32:         webResourceUrl = "/%7B" + webResourceCachingToken + "%7D" + webResourceUrl;
 33:     }
 35:     // Return the URL to the web resource prepended with the organization name if necessary
 36:     return Xrm.Page.context.getServerUrl().replace(/\/$/,"") + Xrm.Page.context.prependOrgName(webResourceUrl);
 37: }

Notice the function takes the name of a web resource, e.g. cei_/mypage.htm, and prepends it with the caching token, organization name if necessary, and the server URL.  Now this function can be used to dynamically generate the URL for a web resource and still retrieve the cached web resource.  Of course, there could be some improvements made,  such as wrapping the call to retrieve the caching token in a closure so that it is only retrieved the first time a URL is generated, but I will leave that up to you.

**Note, that generating a URL in this manner is not supported by Microsoft and the caching mechanism used by CRM for web resources could be changed in the future.


Post by: Nick Doriot, Customer Effective

Show Buttons
Hide Buttons