web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Microsoft Dynamics CRM (Archived)

Best (or recommended) approach to store (cache) configuration data

(0) ShareShare
ReportReport
Posted on by 180

I was wondering about the different ways people may handle configuration data in CRM.
Here are the challenges that I see (and I’m still looking for a solution):

  • Create a dictionary (key value pairs) that can be made available to plugins.
  • Cache this dictionary somehow (one user request can trigger dozens of chained plugins and would be a waste to submit all these requests to retrieve the exactly same data).
  • It should be easy to maintain

I came across these blog posts where the authors mentioned Actions.
I love them and I see many different cases where they are a good fit but not for this one.
Some downsides:

  • In a large application we can have 100+ keys and the Auction UI is not ideal to manage this volume
  • In order to change one single value the whole application needs to be stopped. Prior to edit an action you need to deactivate it. During that time all plugins will fail. This is a huge deal in a large/busy environment.

Dynamics CRM documentation mentions lightweight queries when it comes to metadata.
From MSDN:

You do not have to cache this data because you can use the Microsoft.Xrm.Sdk.Metadata.Query classes to retrieve this data directly from the Microsoft CRM application cache.

I’m not sure what they mean by “Lightweight” query, when looking into a profiler you can see the database is still hit after you submit a metadata request. Perhaps it is just looking for versioning info and this could be where the lightweight comes from?

Anyways, sounds really cool and we could leverage it if only we could add a custom metadata property to an entity, something like “MyData”. Since it is metadata the “Application Cache” would cache all metadata properties (such as “CanCreateViews”) and include “MyData” to it. Sounds too good to be true so we probably can’t do it.

The most appealing approach (from usability point of view) is still storing the configuration on an custom entity but that brings the question: how can we cache it?

Thanks in advance for you comments and/or suggestions.

*This post is locked for comments

I have the same question (0)
  • Verified answer
    Aiden Kaskela Profile Picture
    19,696 on at

    Hi Emerson,

    I've found there are two primary ways people like to keep configurable data in CRM - either have a "settings" entity with many attributes, or a "settings property" entity, with key and value fields, so you'd have many records with each one representing a single property. The difference is preference, I go back and forth on which I like more.

    I like to handle caching by having a static singleton which represents the settings information (either the single record or a list of settings properties). The singleton is shared across plugin processes so there's no waste of hitting the database to retrieve settings over and over. I handle refreshing the settings by keeping track of when the collection was last loaded, and when it passes X minutes it becomes invalidated and is refreshed.

    Hope this helps, and I'd be happy to answer any other questions you might have :) If this was helpful I would love if you could mark this as the verified answer.

    Thanks,

     Aiden

  • Emerson Brito Profile Picture
    180 on at

    Thanks a lot Aiden. It sounds like what I had in mind:

    I was thinking about a plugin base class with a static property (singleton) to hold the configuration.
    I would add an expiration date to the cache (as part of the singleton implementation) just to be safe since a sandboxed plugin won't have a long lifecycle anyways.

    Under heavy load, even though the plugin instance has a short life cycle we would be eliminating a lot of traffic and thousands of database calls.

    Considering the sandbox isolation I believe we will have one instance of the singleton per plugin. This is were I was thinking about the context shared variables to pass the singleton through the chain.

    Is it kind of your approach?

  • Aiden Kaskela Profile Picture
    19,696 on at

    Hi Emerson,

    Even if the plugins are sandboxed, static variables are global to the process so you'll only have one settings object that's shared across all plugins. You'll save a ton of CRM calls to be sure. The only thing you want to be concerned about is making sure to have a lock object for when you refresh the collection to prevent errors from other processes. Something like this:

    private static object settingsLock = new object();
    private static Dictionary<string, string> settingsCollection = null;
    
    public static Dictionary<string, string> Current
    {
     get
     { 
      if //the collection is null or it's stale
      {
       lock (settingsLock)
       {
        if // Check if it's null or stale again since you have the lock now and it could have been refreshed in another thread
        {
          // load the collection and reset the expiration
        }
       }
      }
    return settingsCollection; } }


  • Community Member Profile Picture
    on at

    I think this is not enough.

    Static variable is one for application pool, means for hole CRM. And you definitely not need to mix settings from more organizations together (dev/test, another customers, etc etc)

    So you need to do something like Dictionary<Guid, Dictionary<string, string>>()

    Where first key is organization id and then it is classic cache.

  • Aiden Kaskela Profile Picture
    19,696 on at

    Pavel,

    If you're running your plugins are running in Isolation (which is recommended for On Prem and required for Online), there is no crosstalk from organization to organization. The solution you posted is required if you're not sandboxed but that's not the case here.

    Thanks,

     Aiden

  • Community Member Profile Picture
    on at

    Many ours plugins are not running in sandbox, cos of limitations. So i think this is important note.

    And watchout caching in app farms, if you change setting value and clear cache in server one, server two can have false value then. You need to do some cache synchronization or use shared cache, etc. What is best scenario for this?

    Thanks

  • Emerson Brito Profile Picture
    180 on at

    Pavel,

    I do use an static dictionary, actually a ConcurrentDictionary which handles all the locking behind the scenes saving me a lot of trouble. (msdn.microsoft.com/.../dd287191(v=vs.110).aspx).

    I does get the job done saving lots of database round trips on scenarios where cache doesn't need to be centralized (or synchronized between machines). It all depends on your requirements.

    If I was going to build something that is synced and/or centralized (knowing I would need full trust plugins and therefore it wouldn't work on CRM online), I would start looking at the System.Runtime.Caching namespace.

  • Martin Donnelly Profile Picture
    1,030 on at

    So, we appear to be setting aside Microsoft's proscription of static variables because we have decided the data is constant.  Please consider this specific case.  I want a list of the entity's attributes that are of datatype DateTime (and marked as format.dateonly.)  It would be nice if I didn't have to run a metadata query every time an "upsert" came in.

    Schema is constant over the org, so there doesn't appear to be a syncing problem among distributed servers; the data is very slow moving.  Some other older suggestions use a simple test for null during the Execute method -- if (contactDateFields is null) populate contactDateFields.  This should take care of expiring caches, right?

    Then it would seem that the only concern is that all caches expire whenever a new solution was deployed to the org (or a customization published.)  Are we safe in that assumption?

    My goal is to make the plugin "entity agnostic" -- case contact: doIt(entity, contactDateFields); default: doIt(entity, null); -- where the null argument does go and query the metadata.  Seems to me that if we handle the most popular entities we benefit two ways, less metadata queries AND metadata queries running during "free" milliseconds.

    Comments?  An easier way?

    Thanks much in advance

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > 🔒一 Microsoft Dynamics CRM (Archived)

#1
SA-08121319-0 Profile Picture

SA-08121319-0 4

#1
Calum MacFarlane Profile Picture

Calum MacFarlane 4

#3
Alex Fun Wei Jie Profile Picture

Alex Fun Wei Jie 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans