The Microsoft Dynamics CRM Blog
News and views from the Microsoft Dynamics CRM Team

Storing Configuration Data for Microsoft Dynamics CRM Plug-ins

Storing Configuration Data for Microsoft Dynamics CRM Plug-ins

  • Comments 11

CRM MVP Mitch Milam returns as a guest blogger. You can read more from Mitch at his blog.

One of the benefits to the plug-in architecture of CRM 4.0 is the ability to store plug-ins in the CRM database so they may be used by multiple CRM servers. This introduces a slight complication regarding the storage of configuration information. Because the plug-in assembly doesn’t reside on the disk the normal method of using a .config file located with the assembly no longer works.

Luckily, the plug-in architecture solves this issue by allowing the developer to supply configuration information for each step executed by the plug-in.

Plug-in Configuration Architecture

As noted in the CRM SDK article, Writing the Plug-in Constructor, when creating your plug-in, you may define a constructor that passes two parameters to your plug-in: unsecure configuration and secure configuration:

   1: public class SamplePlugin : IPlugin
   2: {
   3:   public SamplePlugin(string unsecureConfig, string secureConfig)
   4:   {
   5:   }
   6: }

Both parameters are strings and may contain any configuration data, in any format, that you wish. For the purposes of this discussion, we will only be concerned with the unsecure configuration parameter.

Creating a Configuration Structure

Since most of us are familiar with the XML configuration provided by the standard Properties.Settings structure, I thought it would be a great idea to retain as much of that experience as possible so we can move code from a stand-alone test application to a plug-in with little difficulty.

Using an XML fragment that closely resembles the Settings section found in the .config file of a .Net assembly, we can create a similarly functional system for storing configuration data. Consider the following XML:

   1: <Settings>
   2:     <setting name="RetryCount">
   3:         <value>5</value>
   4:     </setting>
   5:     <setting name="TaskPrefix">
   6:         <value>This task was created on {0}.</value>
   7:     </setting>
   8:     <setting name="FirstRun">
   9:         <value>false</value>
  10:     </setting>
  11: </Settings>

As you can see, we have three settings which contain values that we would normally find in our .config file and which are used to configure our assembly. Using the Plug-in Registration Tool, we can add this information to the Unsecure Configuration field when registering a new step, as show by the figure below:

MitchCode

Plug-in Configuration Class

I created a simple class to extract values from an XML document for simple data types such as Guids, strings, Booleans, and integers, given the structure we discussed above:

   1: class PluginConfiguration
   2: {
   3:     private static string GetValueNode(XmlDocument doc, string key)
   4:     {
   5:         XmlNode node = doc.SelectSingleNode(String.Format("Settings/setting[@name='{0}']", key));
   6:  
   7:         if (node != null)
   8:         {
   9:             return node.SelectSingleNode("value").InnerText;
  10:         }
  11:         return string.Empty;
  12:     }
  13:  
  14:     public static Guid GetConfigDataGuid(XmlDocument doc, string label)
  15:     {
  16:         string tempString = GetValueNode(doc, label);
  17:  
  18:         if (tempString != string.Empty)
  19:         {
  20:             return new Guid(tempString);
  21:         }
  22:         return Guid.Empty;
  23:     }
  24:  
  25:     public static bool GetConfigDataBool(XmlDocument doc, string label)
  26:     {
  27:         bool retVar;
  28:  
  29:         if (bool.TryParse(GetValueNode(doc, label), out retVar))
  30:         {
  31:             return retVar;
  32:         }
  33:         else
  34:         {
  35:             return false;
  36:         }
  37:     }
  38:  
  39:     public static int GetConfigDataInt(XmlDocument doc, string label)
  40:     {
  41:         int retVar;
  42:  
  43:         if (int.TryParse(GetValueNode(doc, label), out retVar))
  44:         {
  45:             return retVar;
  46:         }
  47:         else
  48:         {
  49:             return -1;
  50:         }
  51:     }
  52:  
  53:     public static string GetConfigDataString(XmlDocument doc, string label)
  54:     {
  55:         return GetValueNode(doc, label);
  56:     }
  57: }

Putting PluginConfiguration to Work

Once we have our PluginConfiguration class added to our project, we need to modify the plug-in constructor to extract the values from our configuration string:

   1: public SamplePlugin(string unsecureConfig, string secureConfig)
   2: {
   3:     XmlDocument doc = new XmlDocument();
   4:     doc.LoadXml(unsecureConfig);
   5:  
   6:     string TaskPrefix = PluginConfiguration.GetConfigDataString(doc, "TaskPrefix");
   7:     bool FirstRun = PluginConfiguration.GetConfigDataBool(doc, "FirstRun");
   8:     int RetryCount = PluginConfiguration.GetConfigDataInt(doc, "RetryCount");
   9: }

There is no automatic determination of data types so you will need to know which method to use to extract a specific value from the configuration data.

Conclusion

Today we’ve covered how to store configuration information used by a CRM plug-in within the CRM database itself. One of the items you may wish to remember is that each step executed by a plug-in has its own configuration information. If you are using the same configuration data for multiple steps, you will need to set the configuration values to be the same between steps or just insert configuration data that is necessary for a particular step to complete successfully.

Mitch Milam

  • Great post. Would like to share my take on this  -

    I did things differently to store Crm Plugin configuration settings. Took it to the second level and created a custom entity in Crm to hold configuration data. Wrote utility methods to load the configuration using FetchXml and the CrmService reference from IPluginExecutionContext.

    Works like a Charm and love the fact that the settings can be changed easily.

    Cheers,

    Maruf

  • How to manage configuration settings in workflow Activities / Plug-in in CRM 4.0

    This way(that recommended from Microsoft that comes with the registration tool) of manage configuration keys is very "strange" and most likely it is a "default option" – it seems to be that the team who developed the product (that there no question about it – it is a distributed system and it should act like it) forgotten what most developers will have to use: The ability to manage configuration keys and value that can be read and access from any context (Sync plug-in, A-Sync , Workflow activities or from yours ISV web site … ).

    I don't want to paste for every step I have registered a string of XML , I want the ability to hold my keys in one place \ file \ table and that I can access it from any code that runs from at any context.

    From my and our experience there few ways:

    1. Use the default way and read keys from the string that provided with the registration steps Disadvantages: see the above …

    2. Store it in a CRM entity and read it every time from the CRMDisadvantages: There is no Cache managed and every call or read key will get it by the SDK and from the DB – very low performance!!!

    3. Using / Build a Central Configuration Manager that can be read and access at any time from any place and context.This can be achieve by developing a configuration utility that work against .Config file for any system and module.you can to the follow:Create a file name myApp.config and Store it in particular folderPoint the file from the local Machine.config.It will be available from any context , and by default it manage Cache with file dependency.

    Thanks

    ItzikBS

  • ItzikBS -

    Ref to #2 above: You could use a Static Hashtable to hold your configuration data and use null checks to reload if it is gone. Since the plugins are cached, your settings would be cached too.

    Thanks,

    Maruf

  • to maruf_d:

    1. As said, the CRM system is a distributed system, if I have a lot of code and logic, my business logic layer, includes entities handlers, that have the ability to consume a configuration keys and complex values (tell me about a system that’s not have that needs …) I want the ability to manage all of my configuration in one place, get it "quickly" , cache it(with dependency – the data have to be up to date ), managed at the same place (config file, xml, db etc …) and can be available from any context

    about the solution you suggested – I familiar with it, but it is not effective becusase you have to take it mind all of my requirements about cache, one place manager, dependency – I want to get my configuration as part of my BL and jest in plug-in context.

    2. Static Hashtable – will be available only in a Plug-in context, what about WF ? what if I want to use the same keys and even complex values (my configurations can be complex data types such as metadata fields, complex messages strings etc … ) from any place in my application and from any context.

    Thanks

    ItzikBS

  • CRM MVP Mitch Milam returns as a guest blogger with part two of this post. You can read more from Mitch

  • CRM MVP Mitch Milam returns as a guest blogger with part two of this post. You can read more from Mitch

  • CRM MVP Mitch Milam returns as a guest blogger with part two of this post. You can read more from Mitch

  • Are the Dynamics CRM team missing a trick here or is it just a documenation issue ? Having adopted since at least .Net 3.0 a highly distributed SOA - WCF focused architecture, precisely the Workflow logic many of us want to plumb in to Dynamics is absolutely reliant on having serviceModel sections somewhere so as to leverage our existing Services. If not in a "central" place, in at least a documented (supported) location ? I find it hard to recommend a product on the basis that MS say its OK to use machine.config to execute any external calls from WF ? Pls say it aint so..

  • Today we welcome MVP Bill Ryan from CustomerEffective as our guest blogger. In its basic form, CRM 4.0

  • Today we welcome MVP Bill Ryan from CustomerEffective as our guest blogger. In its basic form, CRM 4

  • Today we welcome MVP Bill Ryan from CustomerEffective as our guest blogger. In its basic form, CRM 4

Page 1 of 1 (11 items)
Leave a Comment
  • Please add 4 and 3 and type the answer here:
  • Post