April 2013 - Development Simply Put

A blog simplifies main concepts in IT development and provides tips, hints, advices and some re-usable code. "If you can't explain it simply, you don't understand it well enough" -Albert Einstein

  • Development Simply Put

    If you can't explain it simply, you don't understand it well enough.

    Read More
  • ITWorx

    ITWorx is a global software professional services organization. Headquartered in Egypt, the company offers Portals, Business Intelligence, Enterprise Application Integration and Application Development Outsourcing services to Global 2000 companies.

    Read More
  • Information Technology Institute

    ITI is a leading national institute established in 1993 by the Information and Decision Support Centre.

    Read More

2013-04-23

SharePoint DateTimeControl Issue When Put Inside An Update Panel


SharePoint DateTimeControl Issue When Put Inside An Update Panel

All credits for this post goes to my friend and colleague Mohamed Gamal


When you add a SharePoint DateTimeControl to a webpart inside an update panel and click on the date picker icon, you will receive an "Object Expected” JavaScript error.
<SharePoint:DateTimeControl ID="dtcBirthDate" runat="server" CalendarImageUrl="/_layouts/images/calendar.gif"
CssClassTextBox="itw-longDate" DateOnly="true" LocaleId="7177" ToolTip="Example: 2000-12-31"
DatePickerFrameUrl="/_layouts/iframe.aspx" />


The solution of this error is to just include the datepicker.js file explicitly on the page inside the update panel content template as follows
<script type="text/javascript" src="/_layouts/datepicker.js"></script>


That's it. Hope this will help someone someday :)


2013-04-20

ASP.NET Tips And Hints


ASP.NET Tips And Hints

During my work on ASP.NET projects I passed by a number of problems. Some of these problems may be common and others may be somehow rare. Anyway, I decided to focus on these problems and come up with some sort of patterns to overcome these problems in the future. Don't get me wrong when I said patterns, they are not design patterns, they are just some arrangements which work together to help you not fall in the same mistakes every time.

So, you can look at this topic as a list of tips and hints which may be useful for you while working on ASP.NET projects. May be some of them won't work with your specific business but at least they are good to know.

So, let's start with these tips.


Main Design:
  1. Centralized logging module: you should spend sometime before going deep into your business code to set some grounds for your project to stand on. These grounds include all the non-business related code which you may use repeatedly throughout your project. One of these grounds/modules is the logging module. To know more about this point, you can check Extensible Logging Library For Sharepoint With ULS Logging Support
  2. Centralized settings module: the same concept applies here on the settings module. You should prepare a module which handles all aspects of your code related to saving and retrieving business and non-business settings. For sure you can do this by just using key and value pairs through you code but this may cause you troubles and difficulties when you face a change request or a new security constrain. To know more about this point, you can check How To Centralize Your Web Application Settings And Decouple Your Code From Back-End Dependent Logic & Code
  3. Exposing business related settings: try to expose business related settings and avoid hard-coded values as far as you can because these settings will be subject to frequent change according to the client's needs
  4. Centralized error handling module: one of the basic and frequently used modules is the error handling module. You will find that at many points in your code you need to direct the system user to an error page with a descriptive message beside adding a record in the logging back-end for further investigation and tracking. For sure you can do this on spot every time you need but this is not a good thing as you will need to keep track of every spot you used this code to apply any further changes. So, the best way to do this is to write a single class with the methods you usually use when you handle an error ans start using this class whenever you need.
  5. Centralized constants class: throughout your code you will find yourself use some constants which are related to the environment (ie.: hostname, port number,......) or some internal constants which are used in your code and the client doesn't need to manage or some computed values. Instead of hard-coding these values in more than one place, you can centralize these constants into one class which you can use anywhere in your code when you need to use any of these constants. This way, when you need to change any of these values you will have only one place to visit
  6. Common utilities class: the same applies on utility methods. You will find yourself use some logic repeatedly through your code like converting from string to int with some validation or something like that. In this case, it would be nice to isolate this common logic into one place/class to be used whenever needed
  7. Always use a masterpage: sometimes you feel like you don't need a masterpage but believe me you may regret this. Always use a master page even if it will be just a dummy parent page. This will save you a lot of time and effort when you need to apply some common logic or UI beside it will be painful to re-visit all your pages to apply changes to connect these pages with a masterpage, so, let's do it at the early beginning
  8. Take care of static constructors and try to use "Double Locking": We use static constructors to do some initialization or logic the first time our static class is used. This is very useful and already used in may applications and even design patterns like "Singleton". But, you need to be careful when using static constructors when the code inside deals with an external source or by any mean is subject to exceptions and errors because once an exception raises inside the static constructor you will have to live with the consequences till the application is reset. If you want to know more you can check How To Handle Exceptions Inside Static Constructors - Double Locking Concept
  9. Use separate folder for third party dlls: if you use external third party dlls in your application, create a folder for these dlls other than the "Bin" folder and always add references from this folder
  10. Use automated javascript and css minifying: the js and css files you use may include some comments, spaces, empty lines, ....... these things enlarges the js and css files which consumes more bandwidth and affects performance. You can help reduce this waste of bandwidth by minifying these files before deployment on production environments. For sure you will not do it yourself but you can automate it using some techniques and tools. Here is a useful post which explains one technique to achieve this

DataBound Controls:
  1. One bind method: write only one method which is responsible for binding the control and handling the paging and sorting. This way you will avoid repeated logic and handling the same cases more than once.
  2. Avoid binding when postback: don't bind your control in the page load outside the "!IsPostback" because this will cause some errors and misleading logic. You should keep in mind that every time you click on a button on the page or any other control which causes postback the page load event is executed first before going into the the postback event handler. So, for example if you click on a page number on the pager control, then the page load will be executed first then the "PageIndexChanged" event handler will be executed. So, if you re-bind the control every time you go into the page load event, you will face an error which is telling you you may need to stop the event validation. This is happening because ASP.NET was trying to change the page index in the control as per your request, but before reaching the page index changed event handler you re-bound the control which resets the control and at this point ASP.NET is confused. So, always make sure to not bind the control unless you really need it
  3. Always bind when data is changed: sometimes you think that you don't need to re-bind your control as the change is already done and the control doesn't need to know more. This is not right, every time the data in the datasource change you will need to re-bind the control. You can trust me on this or you can try it yourself
  4. Keep current page index in hidden field: the common behavior between some data-bound controls is that they reset the page index on sorting so that when you change the sorting expression the control returns back to the first page. If you need to keep the page index upon sorting you can keep the page index in a hidden field and always use this field, only update this field when an action happens which updates the page index

General Tips:
  1. Get search values from hidden fields not controls: if you apply searching with some search criteria, then when retrieving data don't get your search criteria values from their corresponding controls directly but get them from hidden fields. This helps you avoid retrieving data upon dummy search criteria unless these criteria are confirmed by hitting the search button. To understand what I am saying, let's say that you have a data grid with paging, user enters value "1" in your search criteria textbox, hits "search", results appear matching the "1", then enters "2" in textbox, hits the arrow on the grid to browse to the second page, then your code will get results matching to the search criteria "2" not "1". This is not logical. So, the best practice is to create a hidden field for every search criteria and update the hidden field value upon clicking the search button. Any time in your code you want to get the value of a search criteria get it from the corresponding hidden field. This way, the criteria will only change when system user hits the search button.
  2. Use URL encoding when needed: whenever you are passing values in a URL use URL encoding and for sure decoding on the other side
  3. Use ClientID: whenever you try to access a server side control from client-side make sure to get its id using ClientID property
  4. Use Encryption/Decryption when needed: whenever you need to pass valuable data between sever and client side think of encrypting and decrypting this data to keep it secure
  5. Validate inputs on both client and server side: don't depend on the client side validation alone and always re-validate inputs on server side. As you know javascript could be disabled on the client browser and this will stop your client side validation. Also, system user can tamper your page using tools like IEDev and this way he can bypass your client side validation logic
  6. Always try to use code generation: always try to use a code generation tool to generate your layers or any other standard code. This makes your code more stable and reliable as these code generation tools are tested and widely used.


That's what I have on mind right now and I will try to keep this list updated. Hope you find something useful in this list.


How To Handle Exceptions Inside Static Constrcutors - Double Locking Concept

Static constructors are very useful but sometimes dangerous in case of depending on an external source or asset.

We use static constructors to do some initialization or logic the first time our static class is used. This is very useful and already used in may applications and even design patterns like "Singleton". But, you need to be careful when using static constructors when the code inside deals with an external source or by any mean is subject to exceptions and errors because once an exception raises inside the static constructor you will have to live with the consequences till the application is reset.

This happened to me once as my application used a static "ConnectionManager" class for my "DAL" and inside the static constructor I wrote some code to get the connection string from an external settings provider (SharePoint list).

This was working fine till by accident someone tampered with the SharePoint list and the static constructor code raised an exception because it couldn't communicate with the list as it should. Then, anytime I try to browse to any page I get a strange error page with an ambiguous stack trace.

So, after some debugging I found the problem and started to think of a way to handle this exception. Sometimes you can do this by just providing a default value to your settings but this time I can't do this because it is a connection string.

So, I found a solution for this problem but before jumping into code let's share some info. The strategy we follow when using the static constructor aims to running some logic only once. The same strategy can be achieved using what we all know as "Singleton" design pattern.

The "Singleton" design pattern itself uses another concept which is known as "Lazy Loading", it is all about running some logic only once. This comes in two flavors, the static constructor and the static property. The .NET framework already makes sure that the logic inside the static constructor runs only once, but on the other hand, the logic inside a static property will run every time the property is called, so this time we have to handle the "only once" part ourselves.

So, let's now see some code.

using System;
using System.Collections.Specialized;
using DevelopmentSimplyPut.CommonUtilities;
using DevelopmentSimplyPut.CommonUtilities.Settings;

namespace DevelopmentSimplyPut.DAL
{
    public static class ConnectionManager
    {
        private static object syncRoot = new Object();

        private static StringDictionary connectionDictionary = new StringDictionary();
        public static StringDictionary ConnectionDictionary
        {
            get
            {
                StringDictionary result = null;

                if (null == connectionDictionary)
                {
                    lock (syncRoot)
                    {
                        if (null == connectionDictionary)
                        {
                            result = new StringDictionary();
                        }
                    }
                }
                
                result = connectionDictionary;
                return result;
            }
            set
            {
                connectionDictionary = value;
            }
        }

  private static string defaultConnectionkey;
        public static string DefaultConnectionkey
        {
            get
            {
                string result = null;

                if (string.IsNullOrEmpty(defaultConnectionkey))
                {
                    lock (syncRoot)
                    {
                        if (string.IsNullOrEmpty(defaultConnectionkey))
                        {
                            try
                            {
                                result = SystemSettingsProvider.GetSettingValue<string>(BusinessSetting.DBConnectionString);
                                ConnectionDictionary.Add("DevelopmentSimplyPutConnectionString", result);
                                DefaultConnectionkey = "DevelopmentSimplyPutConnectionString";
                            }
                            catch (Exception ex)
                            {
                                SystemErrorHandler.HandleError(ex);
                            }
                        }
                    }
                }

                result = defaultConnectionkey;
                return result;
            }
            set
            {
                defaultConnectionkey = value;
            }
        }
    }
}

In the code above you will notice that I am using "lock(){}". This is very important as if your application is multi-threaded then it is probable that more than one thread could be accessing the same static property at the same time and though the logic inside could be applied more than once. So, to avoid this we apply locking so that the first thread reaches the static property will lock and prevent other threads from doing the same till it finishes its work. This is good, but another thing, why do I check if the connection string is equal to null two times one before locking and one after?!!!

What we are asking about now is known as "Double Locking" concept. Since locking is somehow expensive from performance and processing point of view, so we need to try to use it less frequent as much as we can. So, we asked ourselves, when do we need locking??? We need it when we need to prevent other threads from accessing some code. Ok, this is good but don't we already know that all threads will only run the code when the connection string is equal to null and otherwise the static property will return the old connection string? So, the racing between threads will only cause us problems if the connection string is equal to null, otherwise we don't care. So, to save some processing and postpone the locking as much as we can, we first check on the equal to null condition to make sure that we really need to apply locking. So, this justifies the check before the locking. Regarding the check inside the locking, this is required for applying the main lazy loading logic.


That's it. I wish you find this post somehow helpful.


2013-04-12

How To Centralize Your Web Application Settings And Decouple Your Code From Back-End Dependent Logic & Code

Every web application needs some business related settings to be set by the application user to fulfill his needs at certain time. These settings could change from time to time but they are still an asset for the application user and for sure for the application developer.

Sometimes developers deal with settings as if they are some secondary things that should not take much attention. For sure they develop some sort of a methodology to manage it but they don't give it much thinking.

I believe that settings should be treated in a much better way as they represent a very important prospective regarding the business needs and some technical needs. So, why waste this.

Also, sometimes you find that the code is written in a way that makes the business related code is so coupled with the settings back-end storage code. For example; if settings are stored into web.config, you find too many lines of code through the application is accessing the web.config to retrieve the setting value to use it and act accordingly. May be this is acceptable at some point but what if you faced a business need which says that you have to store the settings in a SQL database or a separate XML file or a SharePoint list instead of the web.config???? You think this is too much far to happen .... believe me in the business field it happens.

So, you need to decouple your business code from the code responsible for storing and retrieving your settings values. This is not everything, you also need to centralize your settings and start dealing with them as a main asset which you should make use of.

Imagine that your application user asked you to provide him a decent page with decent UI where he can manage his application settings. This UI should provide some input validations and some good stuff. So, will you go look all around your code to find the settings and then start working on the UI and apply the validations for each field,............. This is good but not that good because every time you find a need for an additional setting you will go back to this page to add your new fields and validations. You will finally notice that most of your code and logic is repeated and this is not good.

So, this is what this post about. After working on a design to help me what I wanted to achieve here, I came out with some code which I really find decent enough to overcome many of the issues I faced before. This code is currently used on a commercial web application for a big company and it approved me right. I am proud of it.

So now it is the time to see some code.


Decoupling business code from settings back-end provider code

SettingsDefinitions.cs
This file includes the definitions (classes, enums, interfaces) which we need to decouple our business code from the code related to the back-end we use to store our settings. Our business code will use these definitions to interact with the settings back-end in an indirect way so that our business code doesn't care if this back-end is a web.config, other XML file, SQL database, Oracle database, NTFS file,..... or any other type of back-end. This is a good thing as anytime we need to modify or change this back-end we will not suffer from changing too many code through the whole application, this is beside the cost of testing all the touched and changed code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevelopmentSimplyPut.CommonUtilities.Settings
{
    [Serializable]
    public class SettingCatalogToken
    {
        public BusinessSetting BusinessSettingName { set; get; }
        public string Category { set; get; }
        public string Key { set; get; }
        public string Description { set; get; }
        public bool Mandatory { set; get; }
        public string DefaultValue { set; get; }
        public string Hint { set; get; }
        public bool RequiresIISReset { set; get; }
        public Func<string, bool> Validator { set; get; }
        public Func<string, object> Converter { set; get; }
    }

    [Serializable]
    public class SettingToken
    {
        public SettingCatalogToken SettingDefinition { set; get; }
        public string Value { set; get; }
        public bool ShowHint { set; get; }
        public SettingToken() { }

        public SettingToken(SettingCatalogToken settingDefinition, string value)
        {
            SettingDefinition = settingDefinition;
            Value = value;
        }
    }

 public enum SettingsProviderType
    {
        ConfigStore = 0,
        WebConfig = 1
    }
 
    public interface ISettingsProvider
    {
        string GetSettingValue(string category, string key);
        void AddSettings(List<SettingToken> entries);
    }

    public class SettingsProviderFactory
    {
        public static ISettingsProvider GetProvider(SettingsProviderType providerType)
        {
            ISettingsProvider provider;

            switch (providerType)
            {
                case SettingsProviderType.ConfigStore:
                    provider = new ConfigStoreSettingsProvider();
                    break;
                case SettingsProviderType.WebConfig:
                    provider = new WebConfigSettingsProvider();
                    break;
                default:
                    provider = GetProvider(InternalConstants.DefaultSystemSettingsProvider);
                    break;
            }

            return provider;
        }
    } 
}

As you can see in the code above, our business code will deal with the interface "ISettingsProvider". Any class implementing this interface is assured to have the two methods "string GetSettingValue(string category, string key)" and "void AddSettings(List<SettingToken> entries)". So, whenever our business code needs to interact with our settings back-end -lets now call it provider- it can use this interface signature and defer/delegate the implementation to the run-time. By the way, the code above makes use of the "Strategy" and "Factory" design patterns.

Now, let's suggest some back-end storage providers for our settings so that we can plug into our application to test our code and the decoupling concept it represents.

For the sake of demonstration, I will assume two providers, one as a web.config and the other is a third party module known as "Config Store" which is used with SharePoint to store and retrieve settings from a SharePoint list.

WebConfigSettingsProvider.cs
This file provides the definition of a class representing a settings provider which depends on a web.config file as its back-end. For sure this class should implement the "ISettingsProvider" interface.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Microsoft.SharePoint.Administration;
using System.Globalization;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using System.Web.Configuration;
using Microsoft.SharePoint;

namespace DevelopmentSimplyPut.CommonUtilities.Settings
{
    public class WebConfigSettingsProvider : ISettingsProvider
    {
        public string GetSettingValue(string category, string key)
        {
            SystemLogger.Logger.LogMethodStart
                (
                    "public string GetSettingValue(string category, string key)",
                    new string[] { "category", "key" },
                    new object[] { category, key }
                );

            string result = string.Empty;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                {
                    try
                    {
                        Configuration config = WebConfigurationManager.OpenWebConfiguration("/", site.WebApplication.Name);
                        if (config.AppSettings.Settings[category.ToLower() + key.ToLower()] != null)
                        {
                            result = config.AppSettings.Settings[category.ToLower() + key.ToLower()].Value;
                            SystemLogger.Logger.LogMethodEnd("public string GetSettingValue(string category, string key)", true);
                        }
                    }
                    catch(Exception ex)
                    {
                        string msg = "Error in retrieveing a setting value from web.config file.";
                        SystemLogger.Logger.LogMethodEnd("public string GetSettingValue(string category, string key)", false);
                        SystemLogger.Logger.LogError(ex, msg);
                        throw;
                    }
                }
            });

            return result;
        }
        public void AddSettings(List<SettingToken> entries)
        {
            SystemLogger.Logger.LogMethodStart
                (
                    "public void AddSettings(SettingToken[] entries)",
                    new string[] { "entries" },
                    new object[] { entries }
                );

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                {
                    try
                    {
                        SPWebService service = SPWebService.ContentService;

                        foreach (SettingToken token in entries)
                        {
                            SPWebConfigModification myModification = new SPWebConfigModification();
                            myModification.Path = "configuration/appSettings";
                            myModification.Name = string.Format(CultureInfo.InvariantCulture, "add[@key=\"{0}\"]", token.SettingDefinition.Category.ToLower() + token.SettingDefinition.Key.ToLower());
                            myModification.Sequence = 0;
                            myModification.Owner = "System";
                            myModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
                            myModification.Value = string.Format(CultureInfo.InvariantCulture, "<add key=\"{0}\" value=\"{1}\"/>", token.SettingDefinition.Category.ToLower() + token.SettingDefinition.Key.ToLower(), token.Value);
                            site.WebApplication.WebConfigModifications.Add(myModification);
                            service.Update();
                            service.ApplyWebConfigModifications();
                        }

                        SystemLogger.Logger.LogMethodEnd("public void AddSettings(SettingToken[] entries)", true);
                    }
                    catch (Exception ex)
                    {
                        string msg = "Error in adding setting entries in web.config file.";
                        SystemLogger.Logger.LogError(ex, msg);
                        SystemLogger.Logger.LogMethodEnd("public void AddSettings(SettingToken[] entries)", false);
                        throw;
                    }
                }
            });
        }
    }
}

As you can see in the code above, the code is dependant on the context it runs inside. For example, the code above runs in a SharePoint environment and that's why it uses some SharePoint APIs to carry out some tasks and logic. But, still our business code doesn't care and this is the beauty of it.

ConfigStoreSettingsProvider.cs
This file provides the definition of a class representing a settings provider which depends on the third party "Config Store" as its back-end. You are not asked to understand every line of code but you should grasp the whole concept behind it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using COB.SharePoint.Utilities;
using Microsoft.SharePoint;
using DevelopmentSimplyPut.CommonUtilities.Logging;

namespace DevelopmentSimplyPut.CommonUtilities.Settings
{
    public class ConfigStoreSettingsProvider : ISettingsProvider
    {
        public string GetSettingValue(string category, string key)
        {
            SystemLogger.Logger.LogMethodStart
                (
                    "public string GetSettingValue(string category, string key)",
                    new string[] { "category", "key" },
                    new object[] { category, key }
                );

            string result = string.Empty;

            try
            {
                result = ConfigStore.GetValue(category, key);
                SystemLogger.Logger.LogMethodEnd("public string GetSettingValue(string category, string key)", true);
            }
            catch (Exception ex)
            {
                SystemLogger.Logger.LogError(ex, "Error in retrieving a setting value from config store list.");
                SystemLogger.Logger.LogMethodEnd("public string GetSettingValue(string category, string key)", false);
                throw;
            }

            return result;
        }
        public void AddSettings(List<SettingToken> entries)
        {
            SystemLogger.Logger.LogMethodStart
                (
                    "public void AddSettings(SettingToken[] entries)",
                    new string[] { "entries" },
                    new object[] { entries }
                );

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.Url))
                {
                    using (SPWeb web = site.RootWeb)
                    {
                        try
                        {
                            web.AllowUnsafeUpdates = true;
                            SPList configStoreList = web.Lists[InternalConstants.ConfigStoreListName];

                            foreach (SettingToken token in entries)
                            {
                                SPQuery query = new SPQuery();
                                query.Query = string.Format
                                    (
                                        CultureInfo.InvariantCulture,
                                        @"<Where>
                                            <And>
                                                <Eq>
                                                    <FieldRef Name='{0}'/>
                                                    <Value Type='{1}'>{2}</Value>
                                                </Eq>
                                                <Eq>
                                                    <FieldRef Name='{3}'/>
                                                    <Value Type='{4}'>{5}</Value>
                                                </Eq>
                                            </And>
                                        </Where>",
                                        ConfigStore.CategoryField,
                                        "Text",
                                        token.SettingDefinition.Category,
                                        ConfigStore.KeyField,
                                        "Text",
                                        token.SettingDefinition.Key);

                                query.ViewFields = "<FieldRef Name='Title'/>";
                                query.RowLimit = 1;

                                SPListItemCollection items = configStoreList.GetItems(query);

                                if (null != items && items.Count > 0)
                                {
                                    string msg = "Setting with category = \"{0}\" and key = \"{1}\" already exists";
                                    SystemLogger.Logger.LogInfo
                                        (
                                            string.Format
                                                (
                                                    CultureInfo.InvariantCulture,
                                                    msg,
                                                    token.SettingDefinition.Category,
                                                    token.SettingDefinition.Key
                                                )
                                        );

                                    foreach (SPListItem item in items)
                                    {
                                        item[ConfigStore.ValueField] = token.Value;
                                        item["ConfigItemDescription"] = token.SettingDefinition.Description;
                                        item.Update();
                                    }
                                    configStoreList.Update();
                                    SystemLogger.Logger.LogInfo("Setting value is updated to \"" + token.Value + "\"");
                                }
                                else
                                {
                                    SPListItem entry = configStoreList.Items.Add();
                                    entry[ConfigStore.CategoryField] = token.SettingDefinition.Category;
                                    entry[ConfigStore.KeyField] = token.SettingDefinition.Key;
                                    entry[ConfigStore.ValueField] = token.Value;
                                    entry["ConfigItemDescription"] = token.SettingDefinition.Description;
                                    entry.SystemUpdate();
                                    configStoreList.Update();
                                }
                            }

                            SystemLogger.Logger.LogMethodEnd("public void AddSettings(SettingToken[] entries)", true);
                        }
                        catch (Exception ex)
                        {
                            SystemLogger.Logger.LogError(ex, "Error in adding setting entries in config store list.");
                            web.AllowUnsafeUpdates = false;
                            SystemLogger.Logger.LogMethodEnd("public void AddSettings(SettingToken[] entries)", false);
                            throw;
                        }
                    }
                }
            });
        }
    }
}

Now, after we have defined our possible settings providers, we can use our factory "SettingsProviderFactory" throughout our business code to get a run-time instance of a provider and start using it by calling the two methods we know. This is good but there is better.

We can write a class which is responsible for choosing the proper provider and handling some logic to finally provide the rest of our code with a settings provider.

SystemSettingsProvider.cs
This file includes a class which handles some logic to choose the proper settings provider and then pass it to our business code. You will find some methods using some classes which are not explained or mentioned yet so don't worry, this will be covered later in this post.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using DevelopmentSimplyPut.CommonUtilities.Helpers;

namespace DevelopmentSimplyPut.CommonUtilities.Settings
{
    public static class SystemSettingsProvider
    {
        private static ISettingsProvider provider;  
        public static T GetSettingValue<T>(BusinessSetting businessSettingName)
        {
            return GetSettingValue<T>(GetSettingCatalogToken(businessSettingName)); 
        }
        public static T GetSettingValue<T>(SettingCatalogToken settingCatalogToken)
        {
            string value = null;
            T result = default(T);

            if (null != settingCatalogToken)
            {
                try
                {
                    value = Provider.GetSettingValue(settingCatalogToken.Category, settingCatalogToken.Key);
                }
                catch (Exception ex)
                {
                    if (settingCatalogToken.Mandatory)
                    {
                        SystemErrorHandler.HandleError(ex, "\"" + settingCatalogToken.Key + "\" setting is not set");
                    }
                    else
                    {
                        value = settingCatalogToken.DefaultValue;
                    }
                }

                if (!settingCatalogToken.Validator(value))
                {
                    if (settingCatalogToken.Mandatory)
                    {
                        SystemErrorHandler.HandleError("Provided \"" + settingCatalogToken.Key + "\" setting is not valid");
                    }
                    else
                    {
                        value = settingCatalogToken.DefaultValue;
                    }
                }

                result = ((T)settingCatalogToken.Converter(value));
            }
            else
            {
                SystemErrorHandler.HandleError(new Exception("SettingToken is not provided into SettingsCatalog"));
            }

            return result;
        }
        public static string TryGetSettingValue(string category, string key)
        {
            string result = string.Empty;

            try
            {
                result = Provider.GetSettingValue(category, key);
            }
            catch (Exception ex)
            {

            }

            return result;
        }
        public static bool UpdateSettings(List<SettingToken> settings)
        {
            bool result = true;
            List<SettingToken> toBeUpdated = new List<SettingToken>();

            if (null != settings && settings.Count > 0)
            {
                foreach (SettingToken token in settings)
                {
                    string value = token.Value;
                    if (!token.SettingDefinition.Validator(value))
                    {
                        token.ShowHint = true;
                        result = false;
                    }
                    else
                    {
                        token.ShowHint = false;
                        toBeUpdated.Add(token);
                    }
                }
            }

            Provider.AddSettings(toBeUpdated);

            return result;
        }
        public static SettingCatalogToken GetSettingCatalogToken(BusinessSetting businessSettingName)
        {
            return SystemSettingsCatalog.SettingsCatalog.DefaultIfEmpty(null).FirstOrDefault(setting => setting.BusinessSettingName == businessSettingName);
        }
        private static void SetProvider(SettingsProviderType providerType)
        {
            SystemLogger.Logger.LogMethodStart
                (
                    "private static void SetProvider(SettingsProviderType providerType)",
                    new string[] { "providerType" },
                    new object[] { providerType }
                );

            try
            {
                provider = SettingsProviderFactory.GetProvider(providerType);
                SystemLogger.Logger.LogInfo("SystemSetitngsProvider is set to " + providerType.ToString());
                SystemLogger.Logger.LogMethodEnd("private static void SetProvider(SettingsProviderType providerType)", true);
            }
            catch (Exception ex)
            {
                SystemLogger.Logger.LogError(ex, "Failed in setting SettingsProviderType");
                SystemLogger.Logger.LogMethodEnd("private static void SetProvider(SettingsProviderType providerType)", false);
                throw;
            }
        }
        private static ISettingsProvider Provider
        {
            get
            {
                if (provider == null)
                {
                    SetProvider(InternalConstants.DefaultSystemSettingsProvider);
                }
                return provider;
            }
        }
        public static void ResetProvider()
        {
            ResetProvider(InternalConstants.DefaultSystemSettingsProvider);
        }
        public static void ResetProvider(SettingsProviderType providerType)
        {
            SetProvider(providerType);
        }
    }
}

As you can see in the code above, this class decides which provider to use and encapsulates some useful logic to be used throughout the rest of the code. So, whenever you need to interact with a settings provider you use this static class methods to achieve what you want.

As I said before, you may have noticed some strange code in the class above that uses some classes that are not defined or explained yet. This code depends on some code I will provide in the second section of this post. This section is talking out how to deal with your settings as an asset.


Settings as an asset

Every setting in your application has some properties which can describe it. Also it has some actions related to it. Doesn't this ring a bell? Isn't this make you shout out loud the word "Class".

This is true, your settings are not just pairs of keys and values. They are a fully qualified class which has its behavior.

For example, if you have in your application a setting which holds a connection string for a SQL database you use throughout the application, don't you want to check if the value provided by the application user is a valid connection string format as you know that it needs to match a certain regular expression? don't you also need to make sure that the value provided represents an online and running SQL database?

If your answer is "Yes", so why do you depend on a helper method in a utility class to do all your checks and you have to call it explicitly whenever you want to verify a connection string? Why don't you keep this verification logic as close as you can to your setting?

Also, If you mark every setting with a key so that you can retrieve this setting from its back-end anytime, why to use a string -array of characters- which you can misspell? why don't you use a more concrete and stable way like enums? This is what I am trying to achieve in the code below.

SystemSettingsCatalog.cs
This file includes an internal catalog which includes all your application settings as fully qualified instances of a fully qualified class encapsulating their verification and conversion logic.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using DevelopmentSimplyPut.CommonUtilities.Helpers;

namespace DevelopmentSimplyPut.CommonUtilities.Settings
{
 public enum BusinessSetting
    {
        DBConnectionString = 0,
        AdminsGroupName = 1,
  GridPageSize = 2,
        AutoCompleteMinCharCount = 3
    }

    public static class SystemSettingsCatalog
    {
        #region Constructor
        static SystemSettingsCatalog()
        {
            settingsCatalog = new Collection<SettingCatalogToken>();
            
   settingsCatalog.Add(new SettingCatalogToken()
            {
                BusinessSettingName = BusinessSetting.DBConnectionString,
                Category = "DevelopmentSimplyPut",
                Key = "DBConnectionString",
                Description = "Connection string of the SQL database",
                DefaultValue = string.Empty,
                Mandatory = true,
                RequiresIISReset = true,
                Hint = "Should be a valid ConnectionString of an online SQL database",
                Validator = new Func<string, bool>
                    (
                        delegate(string settingValue)
                        {
                            string exceptionMessage;
                            return Utilities.VerifySQLConnectionString(settingValue, out exceptionMessage);
                        }
                    ),
                Converter = new Func<string, object>
                    (
                        delegate(string settingValue)
                        {
                            return settingValue;
                        }
                    )
            });
            settingsCatalog.Add(new SettingCatalogToken()
            {
                BusinessSettingName = BusinessSetting.AdminsGroupName,
                Category = "DevelopmentSimplyPut",
                Key = "AdminsGroupName",
                Description = "Name of the Admins users group(s). Users in this/these group(s) will be allowed to access administration pages. Multiple group names should be separated by \",\"",
                DefaultValue = "AdminGroup",
                Mandatory = false,
                RequiresIISReset = false,
                Hint = string.Empty,
                Validator = new Func<string, bool>
                    (
                        delegate(string settingValue)
                        {
                            return true;
                        }
                    ),
                Converter = new Func<string, object>
                    (
                        delegate(string settingValue)
                        {
                            return settingValue;
                        }
                    )
            });
            settingsCatalog.Add(new SettingCatalogToken()
            {
                BusinessSettingName = BusinessSetting.GridPageSize,
                Category = "DevelopmentSimplyPut",
                Key = "GridPageSize",
                Description = "Number of items to be viewed in each page of the system data grids",
                DefaultValue = "20",
                RequiresIISReset = false,
                Mandatory = false,
                Hint = "Should be an integer greater than 0",
                Validator = new Func<string, bool>
                    (
                        delegate(string settingValue)
                        {
                            int result = 0;
                            return (int.TryParse(settingValue, out result) && result > 0);
                        }
                    ),
                Converter = new Func<string, object>
                    (
                        delegate(string settingValue)
                        {
                            return int.Parse(settingValue);
                        }
                    )
            });
            settingsCatalog.Add(new SettingCatalogToken()
            {
                BusinessSettingName = BusinessSetting.AutoCompleteMinCharCount,
                Category = "DevelopmentSimplyPut",
                Key = "AutoCompleteMinCharCount",
                Description = "The minimum number of characters to be entered into the textbox input fields for the auto-complete functionality to start. Please note that the chosen value will affect the system performance, so try to choose a number as large as you can",
                DefaultValue = "10",
                Mandatory = false,
                RequiresIISReset = false,
                Hint = "Should be an integer greater than 0",
                Validator = new Func<string, bool>
                    (
                        delegate(string settingValue)
                        {
                            int result = 0;
                            return (int.TryParse(settingValue, out result) && result > 0);
                        }
                    ),
                Converter = new Func<string, object>
                    (
                        delegate(string settingValue)
                        {
                            return int.Parse(settingValue);
                        }
                    )
            });
        }
        #endregion

        #region SettingsCatalog
        private static Collection<SettingCatalogToken> settingsCatalog;
        public static Collection<SettingCatalogToken> SettingsCatalog
        {
            get
            {
                return settingsCatalog;
            }
        }
        #endregion
    }
}

As you can see in the code above, all info and actions related to an application setting are encapsulated into one class which can be easily managed and extended anytime.

Also, we have a catalog of all our application settings which we can use every time we need to refer to a certain setting or even list all our settings -as we will see later in this post- beside being able to use enums instead of just strings as identifiers for our settings.


The proof

Now, whenever you need to retrieve a value for a certain setting, you can call it as follows
string dbConnectionStr = SystemSettingsProvider.GetSettingValue<string>(BusinessSetting.DBConnectionString);
string adminGroupName = SystemSettingsProvider.GetSettingValue<string>(BusinessSetting.AdminsGroupName);
int gridPageSize = SystemSettingsProvider.GetSettingValue<int>(BusinessSetting.GridPageSize);
int autoCompleteMinCharCount = SystemSettingsProvider.GetSettingValue<int>(BusinessSetting.AutoCompleteMinCharCount);

Also, as a proof of concept, I implemented a settings management page which can be used to change the settings values beside providing some valuable info and validations for user inputs.

Using the code below, you can get a page like the one in this screenshot with just few lines of code. This is beside that whenever you add a new setting to your settings catalog, the page is updated automatically and you don't need to apply any changes.

ManageSettings.aspx
<%@ Page Language="C#" AutoEventWireup="true" enableSessionState="True" Inherits="DevelopmentSimplyPut.Pages.ManageSettings, DevelopmentSimplyPut,  Version=1.0.0.0, Culture=neutral, PublicKeyToken=5b3b2dbf31f780b4" %>

<%@ Import Namespace="DevelopmentSimplyPut.CommonUtilities" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="asp" Namespace="System.Web.UI.WebControls" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" %>
<%@ Register TagPrefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls"
    Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages"
    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls"
    Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Nav" Namespace="Microsoft.SharePoint.Publishing.Navigation"
    Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection" Src="~/_controltemplates/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" Src="~/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection" Src="~/_controltemplates/ButtonSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="Welcome" Src="~/_controltemplates/Welcome.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" Src="~/_controltemplates/DesignModeConsole.ascx" %>
<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" Src="~/_controltemplates/VariationsLabelMenu.ascx" %>
<%@ Register TagPrefix="PublishingConsole" TagName="Console" Src="~/_controltemplates/PublishingConsole.ascx" %>
<%@ Register TagPrefix="PublishingSiteAction" TagName="SiteActionMenu" Src="~/_controltemplates/PublishingActionMenu.ascx" %>
<asp:content id="PageTitle" runat="server" contentplaceholderid="PlaceHolderPageTitle">
    Manage Settings
</asp:content>
<asp:content id="PageTitleInTitleArea" runat="server" contentplaceholderid="PlaceHolderPageTitleInTitleArea">
</asp:content>
<asp:content id="Main" runat="server" contentplaceholderid="PlaceHolderMain">
    <script>
    </script>

 <table cellspacing="0" cellpadding="3" width="100%">
     <tr>
         <td>
             <div id="SettingsGridDiv" runat="server" class="grid">
                 <DevelopmentSimplyPutWebControls:EnhancedDataGrid runat="server"
                 ID="grd_Settings"
                 AutoGenerateColumns="False"
                 AllowPaging="false"
                 AllowSorting="false"
                 PageSize="200"
                 CurrentPageIndex="0"
                 VirtualItemCount="0"
                 ExportToExcel="False"
                 BorderStyle="None"
                 Width="100%"
                 GridLines="None"
                 HorizontalAlign="Center"
                 HorizontalScrollBarVisibility="Hidden"
                 SortingUpImageRelativePath="tri-up.gif"
                 SortingDownImageRelativePath="tri.gif"
                 PagingNextImageRelativePath="rmc/pager_next_arrow.png"
                 PagingPrevImageRelativePath="rmc/pager_perv_arrow.png"
                 CssClass="gridStyle-table">
                 <RowStyle CssClass="gridStyle-tr-data" Wrap="False" />
                 <AlternatingRowStyle CssClass="gridStyle-tr-alt-data" Wrap="False" />
                 <HeaderStyle CssClass="gridStyle-tr-header" />
                  <Columns>
                   <asp:TemplateField HeaderText="Category">
                    <ItemTemplate>
                     <asp:Label  ID="lbl_Category" Text='<%# Eval("SettingDefinition.Category") %>'
                      runat="server" />
                    </ItemTemplate>
                    <ItemStyle CssClass="gridStyle-item-td Category-Css" />
                    <HeaderStyle CssClass="gridStyle-header-th Category-Css" Wrap="true" Width="10%"/>
                   </asp:TemplateField>
                   <asp:TemplateField HeaderText="Key">
                    <ItemTemplate>
                     <asp:Label  ID="lbl_Key" Text='<%# Eval("SettingDefinition.Key") %>'
                      runat="server" />
                    </ItemTemplate>
                    <ItemStyle CssClass="gridStyle-item-td Key-Css" />
                    <HeaderStyle CssClass="gridStyle-header-th Key-Css" Wrap="true" Width="25%"/>
                   </asp:TemplateField>
                   <asp:TemplateField HeaderText="Description">
                    <ItemTemplate>
                     <asp:Label  ID="lbl_Description" Text='<%# Eval("SettingDefinition.Description") %>'
                      runat="server" />
                    </ItemTemplate>
                    <ItemStyle CssClass="gridStyle-item-td Description-Css" />
                    <HeaderStyle CssClass="gridStyle-header-th Description-Css" Wrap="true" Width="35%"/>
                   </asp:TemplateField>
                   <asp:TemplateField HeaderText="IIS Reset?">
                    <ItemTemplate>
                     <asp:Label  ID="lbl_IISReset" Text='<%# ((bool)Eval("SettingDefinition.RequiresIISReset"))? "Yes" : "No" %>'
                      runat="server" />
                    </ItemTemplate>
                    <ItemStyle CssClass="gridStyle-item-td IISReset-Css" />
                    <HeaderStyle CssClass="gridStyle-header-th IISReset-Css" Wrap="true" Width="5%"/>
                   </asp:TemplateField>
                   <asp:TemplateField HeaderText="Value">
                    <ItemTemplate>
                     <asp:TextBox id="txt_Value" TextMode="Multiline" runat="server" Width="95%" Text='<%# Eval("Value") %>'/>
                                    <asp:RequiredFieldValidator ID="vld_txt_Value_NotEmpty" Text="Field is required"  ControlToValidate="txt_Value"
                                    runat="server" Display="Dynamic"/>
                                    <asp:CustomValidator ID="vld_txt_Value" runat="server"
                                    CssClass="ErrorMessage" ControlToValidate="txt_Value" Display="Dynamic"/>
                    </ItemTemplate>
                    <ItemStyle CssClass="gridStyle-item-td Value-Css" />
                    <HeaderStyle CssClass="gridStyle-header-th Value-Css" Wrap="true" Width="25%"/>
                   </asp:TemplateField>
                  </Columns>
                  </DevelopmentSimplyPutWebControls:EnhancedDataGrid>
             </div>
         </td>
     </tr>
     <tr>
         <td style="text-align:right">
             <asp:HiddenField ID="hdn_SubmitClicked" Value="0" runat="server" />
             <asp:Button class="form-button" Text="Submit Changes" ID="btn_Submit" OnClick="btn_Submit_Click" runat="server" />
         </td>
     </tr>
 </table>
</asp:content>

ManageSettings.aspx.designer.cs
using System.Web.UI.WebControls;
using AjaxControlToolkit;
using DevelopmentSimplyPut.CommonUtilities.WebControls;
using System.Web.UI.HtmlControls;

namespace DevelopmentSimplyPut.Pages
{
    public partial class ManageSettings
    {
        protected EnhancedDataGrid grd_Settings;
        protected Button btn_Submit;
        protected HiddenField hdn_SubmitClicked;
        protected global::System.Web.UI.HtmlControls.HtmlGenericControl SettingsGridDiv;
    }
}

ManageSettings.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using System.Web.Configuration;
using Microsoft.SharePoint;
using System.Configuration;
using DevelopmentSimplyPut.CommonUtilities;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using DevelopmentSimplyPut.CommonUtilities.Settings;
using DevelopmentSimplyPut.CommonUtilities.Security;
using DevelopmentSimplyPut.CommonUtilities.Helpers;
using System.Drawing;
using System.Data;
using DevelopmentSimplyPut.Entities;
using DevelopmentSimplyPut.BusinessLayer;
using DevelopmentSimplyPut.CommonUtilities.WebControls;
using System.Collections.ObjectModel;
using System.Web.UI.HtmlControls;
using System.Globalization;

namespace DevelopmentSimplyPut.Pages
{
    public partial class ManageSettings : BasePage
    {
        #region Events
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BindData();
            }
        }
        protected void btn_Submit_Click(object sender, EventArgs e)
        {
            if (null != Session["SettingsGridDataSource"])
   {
    List<SettingToken> lst = new List<SettingToken>();
    List<SettingToken> source = (List<SettingToken>)Session["SettingsGridDataSource"];
    foreach (GridViewRow row in grd_Settings.Rows)
    {
     if (row.RowType == DataControlRowType.DataRow)
     {
      SettingToken token = source[row.RowIndex];
      string newValue = ((TextBox)row.FindControl("txt_Value")).Text;
      CustomValidator validatior = (CustomValidator)row.FindControl("vld_txt_Value");

      if (!token.SettingDefinition.Validator(newValue))
      {
       token.ShowHint = true;
       validatior.IsValid = false;
       validatior.ErrorMessage = token.SettingDefinition.Hint;
      }
      else
      {
       token.ShowHint = false;
       validatior.IsValid = true;
       lst.Add(token);
      }

      token.Value = newValue;
     }
    }

    SystemSettingsProvider.UpdateSettings(lst);
   }
        }
        #endregion
        #region Methods
        private void BindData()
        {
            try
            {
                SystemLogger.Logger.LogMethodStart("BindData()", null, null);

                List<SettingToken> settings = GetSettinngs();

                if (null != settings && settings.Count > 0)
                {
                    grd_Settings.Visible = true;
                    SettingsGridDiv.Visible = true;
                    grd_Settings.PageIndex = 0;
                    grd_Settings.VirtualItemCount = settings.Count;
                    Session["SettingsGridDataSource"] = settings;
                    grd_Settings.DataSource = settings;
                    grd_Settings.DataBind();
                }
                else
                {
                    SettingsGridDiv.Visible = false;
                    grd_Settings.Visible = false;
                }

                SystemLogger.Logger.LogMethodEnd("BindData()", true);
            }
            catch (Exception ex)
            {
                SystemLogger.Logger.LogError(ex.Message);
                SystemLogger.Logger.LogMethodEnd("BindData()", false);
                SystemErrorHandler.HandleError(ex);
            }
        }
        private List<SettingToken> GetSettinngs()
        {
            List<SettingToken> result = new List<SettingToken>();

            foreach (SettingCatalogToken token in SystemSettingsCatalog.SettingsCatalog)
            {
                string value = SystemSettingsProvider.TryGetSettingValue(token.Category, token.Key);
                value = (string.IsNullOrEmpty(value)) ? string.Empty : value;

                SettingToken finalToken = new SettingToken();
                finalToken.SettingDefinition = token;
                finalToken.Value = value;

                if (!token.Validator(value))
                {
                    finalToken.ShowHint = true;
                }
                else
                {
                    finalToken.ShowHint = false;
                }

                result.Add(finalToken);
            }

            return result;
        }
        #endregion
    }
} 

As you can see, it is too easy to believe. Finally, here are some code of helping classes I used.

InternalConstants.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using DevelopmentSimplyPut.CommonUtilities.Settings;
using DevelopmentSimplyPut.CommonUtilities.Security;
using DevelopmentSimplyPut.CommonUtilities.Helpers;
using Microsoft.SharePoint;
using System.Collections.ObjectModel;

namespace DevelopmentSimplyPut.CommonUtilities
{
    public static class InternalConstants
    {
        #region Settings Provider
        public static SettingsProviderType DefaultSystemSettingsProvider
        {
            get
            {
                return SettingsProviderType.ConfigStore;
            }
        }
        public static string ConfigStoreListName
        {
            get
            {
                return "Config store";
            }
        }
  #endregion
    }
}

Utilities.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Common;
using System.Data.SqlClient;
using System.Web;

namespace DevelopmentSimplyPut.CommonUtilities.Helpers
{
    public static class Utilities
    {
        /// <summary>
        /// Checks whether a given string represents a valid and online ConnectionString for a SQL database
        /// </summary>
        /// <param name="connectionString">String to be verified</param>
        /// <param name="exceptionMessage">Output exception message if exists</param>
        /// <returns></returns>
        public static bool VerifySQLConnectionString(string connectionString, out string exceptionMessage)
        {
            bool result;

            try
            {
                DbConnectionStringBuilder csb = new DbConnectionStringBuilder();
                csb.ConnectionString = connectionString;

                try
                {
                    using (SqlConnection conn = new SqlConnection(connectionString))
                    {
                        conn.Open();
                    }

                    exceptionMessage = null;
                    result = true;
                }
                catch(Exception ex)
                {
                    exceptionMessage = ex.Message;
                    result = false;
                }  
            }
            catch(Exception ex)
            {
                exceptionMessage = ex.Message;
                result = false;
            }

            return result;
        }
    }
}

SystemErrorHandler.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevelopmentSimplyPut.CommonUtilities.Logging;
using System.Globalization;
using System.Web.UI;
using System.Web;

namespace DevelopmentSimplyPut.CommonUtilities
{
    public static class SystemErrorHandler
    {
        public static void HandleError(Exception ex, string message)
        {
            string guid = System.Guid.NewGuid().ToString();
            SystemLogger.Logger.LogError(string.Format(CultureInfo.InvariantCulture, "Unexpected error start, GUID = \"{0}\"", guid));

            if (null != ex)
            {
                SystemLogger.Logger.LogError(ex, message);
            }
            else
            {
                SystemLogger.Logger.LogError(message);
            }

            SystemLogger.Logger.LogError(string.Format(CultureInfo.InvariantCulture, "Unexpected error end, GUID = \"{0}\"", guid));
            HttpContext.Current.Response.Redirect
                (
                    string.Format
                    (
                        CultureInfo.InvariantCulture,
                        "{0}/Error.aspx?generalmsg={1}&msg={2}&guid={3}",
                        InternalConstants.PagesDirectoryAbsolutePath,
                        HttpContext.Current.Server.UrlEncode(InternalConstants.UnexpectedErrorMsg),
                        HttpContext.Current.Server.UrlEncode(message),
                        HttpContext.Current.Server.UrlEncode(guid)
                    ), true
                );
        }
        public static void HandleError(Exception ex)
        {
            HandleError(ex, string.Empty);
        }
        public static void HandleError(string message)
        {
            HandleError(new Exception(".."), message);
        }
        public static void HandleError(string exceptionMessage, string message)
        {
            HandleError(new Exception(exceptionMessage), message);
        }
    }
}


You can download the code from here