Pogo69's Blog

October 29, 2010

To Cache or Not to Cache – CRM 4.0 SDK – Advanced Developer Extensions

Filed under: CRM — Tags: , , — pogo69 [Pat Janes] @ 00:05

Let’s face it; I’m a bit lucky with respect to my relatively recent introduction to Microsoft Dynamics CRM. I’ve entered the game to find a robust (most of the time AKA when it behaves) and mature product, without many of the restrictions and idiosyncrasies of earlier versions. I’ve still never even seen a CRM 3.0 or earlier system; and between you, me and the world, I’d like to keep it that way. Soon, we’ll see the introduction of CRM2011, which appears to be a developer’s dream – more customisation, packaged “solutions”, more in-depth integration, a more mature client and server object model.

But back to CRM 4.0. The biggest change brought by the most recent release of the CRM 4.0 SDK was the Advanced Developer Extensions (Microsoft xRM *). It allows developers to access CRM entity instances via LINQ; a set of extension methods introduced to C# to allow SQL like syntax querying of an appropriately mapped object model. So, by ditching the old unwieldy QueryExpression syntax, what would formerly have taken dozens of lines of code, can now be expressed by its far more compact (and far more maintainable) equivalent. Something like:

List<Xrm.mrc_coursesubject> subjects =
	(
		from s in DataContext.mrc_coursesubjects
		join sa in DataContext.mrc_coursesubjectallocations on s.mrc_coursesubjectid equals sa.mrc_subjectid.Value
		join cs in DataContext.mrc_courseschedules on sa.mrc_courseid.Value equals cs.mrc_courseid.Value
		where cs.mrc_coursescheduleid == this._courseScheduleId
		select s
	).ToList();

subjects.ForEach(subject =>
		this.ddlSubject.Items.Add(new ListItem(subject.mrc_name, subject.mrc_coursesubjectid.ToString()))
	);

I won’t go further into it in this posting, but keep an eye out for a subsequent posting on some of the idiosyncrasies of CRM specific LINQ queries.

So… caching.

The xRM libraries ship with an inbuilt caching mechanism; also recently released were new versions of what have been termed “Accelerators”.  These complete reference websites are built around a CRM-driven CMS * system.  Because almost everything you see in the Accelerator websites is dynamically generated from entity instances in the CRM, it is very important that the data is cached appropriately.

This, however, has created a number of issues for developers hoping to use the xRM libraries to dynamically display CRM content on their 3rd party websites. Newly created/updated/deleted CRM data is not immediately viewable as previously obtained results are cached.  The documentation makes some reference to the caching mechanisms involved, but not enough to make it immediately obvious how to turn it off, and/or control it to meet your requirements.  While I don’t profess to understand every intricacy of the xRM caching framework, the following outlines what I did to meet our clients’ needs and it has certainly worked for us.

Basically, we pre-process every incoming page request in the ASP.NET Application File, Global.asax; empty functions elided for simplicity and clarity:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

namespace Namespace.Of.The.Week
{
	public static class Extensions
	{
		public static void RemoveAll(this Microsoft.Xrm.Client.Caching.BaseCache cache)
		{
			foreach (KeyValuePair<string, object> pair in (IEnumerable<KeyValuePair<string, object>>)cache)
			{
				cache.Remove(pair.Key);
			}
		}
	}

	public class Global : System.Web.HttpApplication
	{
		#region Helper Routines
		private static void ClearCache(string entityName)
		{
			var dependency = string.Format("adxdependency:crm:entity:{0}", entityName).ToLower();

			var cache = Microsoft.Xrm.Client.Caching.CacheManager.GetBaseCache();
			cache.Remove(dependency);
		}
		private static void ClearCache()
		{
			Microsoft.Xrm.Client.Caching.CacheManager.GetBaseCache().RemoveAll();
		}
		#endregion

		protected void Application_BeginRequest(object sender, EventArgs e)
		{
			string cacheRemoval = System.Configuration.ConfigurationManager.AppSettings["Cache.Removal"];

			switch (cacheRemoval.ToLower())
			{
				case "all":
					// clear all cache items for the following entities
					ClearCache();
					break;

				case "entity":
					string[] entities = System.Configuration.ConfigurationManager.AppSettings["Cache.Removal.Entities"].Split(new char[] { ',' });
					foreach (string entity in entities)
					{
						ClearCache(entity);
					}
					break;
			}
		}

		...
	}
}

* xRM – Anything (x) Relationship Management

* CMS – Content Management System

5 Comments »

  1. What DLL is Microsoft.Xrm.Client.Caching.CacheManager in? I can’t find it in the Xrm.Client or Xrm.Sdk

    Comment by Chris Lee — June 10, 2011 @ 07:45

    • Hey Chris.

      It is in the Microsoft.Xrm.Client.dll assembly – but note this applies only to the CRM 4.0 Xrm assemblies.

      Comment by pogo69 — June 14, 2011 @ 09:40

  2. Hello.

    This is not the best solution, because when two or more users make the same query , and then try to clear the cache, as a result an error occured:

    System.UnauthorizedAccessException:
    Message: Access to the path ‘appDomain=/LM/W3SVC/2/Root/…:key=Microsoft.Xrm.Client.Services.InMemoryCrmCacheProvider:1177205267:User=00000000-0000-0000-0000-000000000000,00000000-0000-0000-0000-000000000000:Query=-107068185’ is denied.

    That’s because user2 clears the cache for user1.

    So, the solution is:

    1) When you use Xrm client, after update/create/delete operations, cache will be cleaned automatically. And you don’t need to use your custom mechanism of cleaning cache.

    2) If you don’t need in caching your queries, you can turn it off (disabled XRM caching). In XRM SDK this solution is described. Do the following:
    CrmConnection xrmConnection = CrmConnection.Parse(Configuration.AppSettings[“XrmConnectiontWithImpersonate”]); // use your own connection string, for example like this “Authentication Type=Integrated; Server=http://crmserver:/orgname/”
    DataContext xrmDataContextWithImpersonate_CacheDisabled = new DataContext(“CacheDisabled”, () => new OrganizationService(“CacheDisabled”, xrmConnection));

    Best Regards, Alexey.

    Comment by Alexey — October 24, 2011 @ 17:21

    • Cheers Alexey,

      I’m sure I would have run across this issue at some point – good to know how to properly deal with it.

      –pogo (pat)

      Comment by pogo69 — November 23, 2011 @ 14:35

  3. […] https://pogo69.wordpress.com/2010/10/29/to-cache-or-not-to-cache-crm-4-0-sdk-advanced-developer-exten… (read comments area). Tags: Leave a comment | Trackback No comments yet. […]

    Pingback by CRM portal Cache -Kevin's Mocha — May 22, 2012 @ 07:40


RSS feed for comments on this post. TrackBack URI

Leave a reply to pogo69 Cancel reply

Blog at WordPress.com.