Storing Custom Settings in Dynamics CRM 2011

Gayan Perera, 07 April 2012

While browsing the Dynamics CRM 2011 Development forum I came across a post asking where people store their settings for ISV extensions.

The way we’ve done this is by creating a custom entity called “Settings” with 3 fields, Key, Value and Encrypted (yes/no).

Example:

Storing Custom Settings in Dynamics CRM 2011 

Then we have a helper class that gets these values. Here’s an example

Inside a Plugin

IOrganizationService ios = factory.CreateOrganizationService(…);
Setting settings = new Setting(ios);
 
int defaultDays = settings.Get<int>("complaint.default.acknowledgementdeadlinedays");

The Settings.cs file

Couple of things to note, the EncryptDecrypt method is blanked out, you’ll need to implement your own encryption and decryption routine. The Get method only has a few known type castings, add more as required.

public class Setting
{
    private IOrganizationService _sdk = null;
    public Setting(IOrganizationService context)
    {
        _sdk = context;
    }
 
    #region encryption
    internal static string EncryptDecrypt(string textToEncrypt)
    {
        return textToEncrypt; // up to you to implement encryption
    }
    #endregion
 
    // some common type castings, you can add more if required
    public T Get<T>(string key)
    {
        string value = this[key];
        if (!string.IsNullOrEmpty(value))
        {
            if (typeof(T) == typeof(string))
            {
                return (T)Convert.ChangeType(value, typeof(string));
            }
 
            if (typeof(T) == typeof(int))
            {
                return (T)Convert.ChangeType(int.Parse(value), typeof(int));
            }
 
            if (typeof(T) == typeof(decimal))
            {
                return (T)Convert.ChangeType(decimal.Parse(value), typeof(decimal));
            }
 
            if (typeof(T) == typeof(DateTime))
            {
                return (T)Convert.ChangeType(DateTime.Parse(value), typeof(DateTime));
            }
        }
 
        return default(T);
    }
 
    #region settings storage
    private Dictionary<string, string> _values = new Dictionary<string, string>();
    private Dictionary<string, Guid> _cached = new Dictionary<string, Guid>();
 
    internal string this[string key]
    {
        get
        {
            if (_values == null || _values.Count == 0) { Refresh(); }
            if (_values.Keys.Contains(key))
            {
                return _values[key];
            }
 
            return "";
        }
        set
        {
        }
 
    }
    #endregion
 
    #region helper methods
    public void Refresh()
    {
        _cached.Clear();
 
        // get all the settings and parse it into a collection first
        QueryExpression qe = new QueryExpression("mag_setting") { ColumnSet = new ColumnSet(true) };
        var results = _sdk.RetrieveMultiple(qe);
 
        if (results != null && results.Entities != null && results.Entities.Count > 0)
        {
            results.Entities.ToList().ForEach(setting =>
            {
                var current = setting as Entity;
 
                Guid id = current.Get<Guid>("mag_settingid");
                bool encrypted = current.Get<bool>("mag_encrypted");
                string key = current.Get<string>("mag_key");
                string value = current.Get<string>("mag_value");
                if (encrypted) { value = EncryptDecrypt(value); } // decrypt if the setting is encrypted
 
                // make sure we don't double up on the settings, otherwise .net will throw an error
                if (!_cached.Keys.Contains(key)) { _cached.Add(key, id); }
                if (!_values.Keys.Contains(key)) { _values.Add(key, value); }
            });
        }
    }
    #endregion
}