Friday 10 February 2017

How to pass configuration parameters in plugins in MS Dynamics CRM

How to pass configuration parameters in plugins in MS Dynamics CRM


Many times, we face a situation where we need to hard-code things in plugins which we know might get changed in future. 
For ex:
1. If we are sending emails from plugins, we might need to hard-code the name/guid of the sender queue, which in-face might be different for different instances.
2. When we are sending SMS' using plugin and have url of SMS vendor which we need to hit in order to send the SMS. We have to hard-code url in plugin code itself.
I'm sure there are many more scenario where we have to hard-code things which we wish we can keep configurable for future change scope.

In this post, we'll discuss how we can pass parameters to our plugin code and in what way so that it can be easily modified with minimum efforts.

I'm sure you have seen the below highlighted boxes while registering the step of a plugin:

So for what they are used?

These are used to pass configuration to plugins.

There are 2 ways of doing that:
1. Unsecure configuration
2. Secure Configuration

So what is the difference b.w these 2 types?

Below is the difference b/w these 2 types:-
Unsecure Config Secure Config
Readable by any CRM User Yes No
Moves Between Environments with Solutions Yes No
Available when Plugin is Registered for Outlook Offline Mode Yes No


So how do we pass it through any of the above method?

In this post we'll discuss how we can pass different type of parameters to plugin.

For demonstration, we'll pass 4 types of parameters to a plugin running on contact i.e.
1. String
2. Integer
3. Boolean
4. Guid
and will show that these are actually passed by updating all parameters into the description field.

I'm sure passing parameter is way more useful than storing it in the description..!!
You can use it as per your requirement.

We created a class named PluginConfiguration in our plugin having below code:-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace PluginConfigurationTest
{
    class PluginConfiguration
    {
        private static string GetValueNode(XmlDocument doc, string key)
        {
            XmlNode node = doc.SelectSingleNode(String.Format("Settings/setting[@name='{0}']", key));

            if (node != null)
            {
                return node.SelectSingleNode("value").InnerText;
            }
            return string.Empty;
        }

        public static Guid GetConfigDataGuid(XmlDocument doc, string label)
        {
            string tempString = GetValueNode(doc, label);

            if (tempString != string.Empty)
            {
                return new Guid(tempString);
            }
            return Guid.Empty;
        }

        public static bool GetConfigDataBool(XmlDocument doc, string label)
        {
            bool retVar;

            if (bool.TryParse(GetValueNode(doc, label), out retVar))
            {
                return retVar;
            }
            else
            {
                return false;
            }
        }
        public static int GetConfigDataInt(XmlDocument doc, string label)
        {
            int retVar;

            if (int.TryParse(GetValueNode(doc, label), out retVar))
            {
                return retVar;
            }
            else
            {
                return -1;
            }
        }

        public static string GetConfigDataString(XmlDocument doc, string label)
        {
            return GetValueNode(doc, label);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
For demo purpose, we have set the step to fire on change of fax and extracted the passed parameters and stored them in the description of contact.

Below is the code of our plugin class file where we extracted the parameters from xml by parsing it with the help of PluginConfiguration:-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using Microsoft.Xrm.Sdk;
using System.Xml;

namespace PluginConfigurationTest
{
    public class ConfigTest : IPlugin
    {
        String  stringParam = String.Empty;
        int integetParam;
        bool boolParam;
        Guid guidParam = Guid.Empty;
        //Created a constructor to initialize the variable with passed parameters
        public ConfigTest(string unsecureString, string securedString)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(unsecureString);
                stringParam= PluginConfiguration.GetConfigDataString(doc, "string");
                integetParam = PluginConfiguration.GetConfigDataInt(doc, "int");
                boolParam = PluginConfiguration.GetConfigDataBool(doc, "bool");
                guidParam = PluginConfiguration.GetConfigDataGuid(doc, "guid");

            }
            catch (Exception ex)
            {

                throw new Exception("Error " + ex.Message);
            }
        }
        public void Execute(IServiceProvider serviceProvide)
        {
            #region SetUp
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvide.GetService(typeof(IPluginExecutionContext));
            IOrganizationService service = ((IOrganizationServiceFactory)serviceProvide.GetService(typeof(IOrganizationServiceFactory))).CreateOrganizationService(context.UserId);
            #endregion
            if ((context.InputParameters.Contains("Target")) && (context.InputParameters["Target"] is Entity) & context.Depth < 3)
            {
                Entity entity = (Entity)context.InputParameters["Target"];
                if (entity.LogicalName != "contact")
                    return;
                try
                {
                    entity["description"] = "1." + stringParam + "\n2." + integetParam + "\n3." + boolParam + "\n4." + guidParam.ToString();
                    service.Update(entity);
                }
                catch (Exception ex)
                {
                    throw new Exception("Error " +ex.Message);
                }
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



Below is the xml we created to be passed in plugin step:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 <Settings>
       <setting name="string">
           <value>Vishal Kumar</value>
       </setting>   
  <setting name="int">
           <value>23</value>
       </setting>   
   <setting name="bool">
           <value>true</value>
       </setting>   
   <setting name="guid">
           <value>6F6A7298-53EF-E611-8111-C4346BDC3C21</value>
       </setting>   
   </Settings>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
We need to put this xml to in unsecure configuration box and update the step to pass this to the plugni on this step.
Below is the plugin step for reference:-



Below is the  output of the plugin on the contact record:-
I hope the post was helpful.

You can utilize the feature to pass parameters to plugins and change those whenever needed.