How To Handle Exceptions Inside Static Constrcutors - Double Locking Concept

Posted by Ahmed Tarek Hasan on 4/20/2013 03:30:00 PM with No comments
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.



Categories: , ,