Sunday 29 November 2015

ConcurrentDictionary or Dictionary with lock

You may already know that there are 2 types of dictionary classes available in .NET framework - Dictionary and ConcurrentDictionary.

ConcurrentDictionary is possibly the right choice in cases when you have to maintain a static dictionary in an application where parallel access to the dictionary is possible. Surely you can do the same with a Dictionary instance but then you have to write lock statements around dictionary operation statements.

How about comparing the performance overhead between the two approaches. I wrote a simple utility that performs random read/write/delete operations on the two types and measure any difference. To my surprise, I did not see any big difference. Both approaches showed similar numbers :)

        private static bool shouldStop = false;
        private static object lockObj = new object();
        private static Dictionary dict = new Dictionary();
        private static ConcurrentDictionary dict2 = new ConcurrentDictionary();
        private static Random r = new Random();
        private static string[] OperationsList = new string[11]
        {
            "R", "W", "R", "W", "D", "R", "R", "R", "R", "W", "D"
        };

        static void Main(string[] args)
        {
            dict.Add("A", "B");
            dict2.GetOrAdd("A", "B");
            Console.WriteLine("Starting...");
            Task t = new Task(RunDictionaryTest);
            t.Start();
            Console.ReadKey();
            shouldStop = true;
            Console.WriteLine("Stopping...");
        }

        private static void RunDictionaryTest()
        {
            Action a = () =>
            {
                Console.WriteLine("Running...");
                while (!shouldStop)
                {
                    var number = r.Next(0, 10);
                    ////DoRandomDictionaryTryGetOperation(OperationsList[number]);
                    DoRandomDictionaryOperationWithContainsKey(OperationsList[number]);

                    ////DoRandomConcurrentDictionaryOperation(OperationsList[number]);
                    ////Thread.Sleep(10);
                }
            };

            Task[] tasks = new Task[100];
            for (int i = 0; i < 100; i++)
            {
                tasks[i] = new Task(a);
            }

            for (int i = 0; i < 100; i++)
            {
                tasks[i].Start();
            }

            Task.WaitAll(tasks);
        }

        private static void DoRandomConcurrentDictionaryOperation(string operationName)
        {
            string val;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            switch (operationName)
            {
                case "R":
                    if (dict2.TryGetValue("Key", out val))
                    {
                        Console.WriteLine("Read:" + val);
                    }
                    else
                    {
                        Console.WriteLine("No Read");
                    }
                    break;
                case "W":
                    val = Guid.NewGuid().ToString();
                    string val2 = dict2.AddOrUpdate("Key", val, (k, v) => val);
                    if (!val.Equals(val2))
                    {
                        Console.WriteLine("no write");
                    }
                    break;
                case "D":
                    if(!dict2.TryRemove("Key", out val))
                    {
                        Console.WriteLine("no delete");
                    }
                    break;
            }
            sw.Stop();
            Console.WriteLine("Time taken" + sw.ElapsedMilliseconds.ToString());
        }

        private static void DoRandomDictionaryTryGetOperation(string operationName)
        {
            string val;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            switch (operationName)
            {
                case "R":
                    lock (lockObj)
                    {
                        if (dict.TryGetValue("Key", out val))
                        {
                            Console.WriteLine("Read:" + val);
                        }
                        else
                        {
                            Console.WriteLine("No Read");
                        }
                    }
                    break;
                case "W":
                    lock (lockObj)
                    {
                        if (dict.TryGetValue("Key", out val))
                        {
                            Console.WriteLine("no write");
                        }
                        else
                        {
                            dict.Add("Key", Guid.NewGuid().ToString());
                        }
                    }
                    break;
                case "D":
                    lock (lockObj)
                    {
                        if (dict.TryGetValue("Key", out val))
                        {
                            dict.Remove("Key");
                        }
                        else
                        {
                            Console.WriteLine("no delete");
                        }
                    }
                    break;
            }
            sw.Stop();
            Console.WriteLine("Time taken" + sw.ElapsedMilliseconds.ToString());
        }

        private static void DoRandomDictionaryOperationWithContainsKey(string operationName)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            switch (operationName)
            {
                case "R":
                    lock (lockObj)
                    {
                        if (dict.ContainsKey("Key"))
                        {
                            Console.WriteLine("Read:" + dict["Key"]);
                        }
                        else
                        {
                            Console.WriteLine("No Read");
                        }
                    }
                    break;
                case "W":
                    lock (lockObj)
                    {
                        if (dict.ContainsKey("Key"))
                        {
                            Console.WriteLine("no write");
                        }
                        else
                        {
                            dict.Add("Key", Guid.NewGuid().ToString());
                        }
                    }
                    break;
                case "D":
                    lock (lockObj)
                    {
                        if (dict.ContainsKey("Key"))
                        {
                            dict.Remove("Key");
                        }
                        else
                        {
                            Console.WriteLine("no delete");
                        }
                    }
                    break;
            }
            sw.Stop();
            Console.WriteLine("Time taken" + sw.ElapsedMilliseconds.ToString());
        }

Wednesday 18 November 2015

.NET applications and HTTP proxies

Accessing web resources using .NET's WebRequest class is such a common task that it is almost a given that it should qualify "write once and run everywhere". Yet, it does not. A simple code block to make HTTP requests start to fail as soon as it is moved to a non-dev machine :).

Almost all of the cases end up being related to the way HTTP proxies have been configured in a different environment and that the machines can not be make HTTP requests without going to proxy. The situation becomes grimmer when there are tricky configurations like URL1 is allowed to be accessed without proxy and URL2 is not allowed to be accessed without proxy. The mire!!

to the rescue then. The Internet is full with solutions that talk about this holy .NET configuration element at length and at the same time complain how Microsoft missed a trick by not enabling proxy as a default setting.

So what do we do in such cases?

1. If all the traffic is allowed through proxy then you can simply update the config file of the application with defaultProxy/Proxy element.
2. If there is a list of URLs that need to be bypassed, then additional element needs to be added.



Where do we add this entries?

Go in this order:
1. If it is for just one application, use configuration file of the application.
2. If it is to be done for all applications on the machine
  • If it is a desktop application, update machine.config of the appropriate .NET version folder (there are pitfalls like Framework and Framework64 :) )
  • If it is a web application hosted in IIS, update the web.config located at the same location where machine.config is generally found. I learned it the hard way.
Let us hope, no one runs into proxy issues again. Ever!!

Wednesday 4 November 2015

Why do you have multiple X-Frame-Option values?

X-Frame-Options are extremely useful and are so good that ASP.NET MVC emits this header automatically unless explicitly specified. While it is a must for any enterprise grade Web application, ASP.NET MVC based implementation has an interesting issue - multiple values for the header which can conflict with the headers configured through web.config file and cause unwanted behavior.

When does ASP.NET MVC produce multiple values for this header? Well, the secret lies in the implementation of "AntiForgeryToken" method of HtmlHelper class. If you open up the implementation in reflector/ILSpy, you will notice the implementation of GetFormInputElement.















Essentially, if the page hierarchy has multiple instances of Html.AntiforgeryToken() (whether in same page or through multiple partial views), then ASP.NET MVC adds one header value for each instance, thus resulting in multiple values for same header. Of course, as you know, you can suppress that behavior but it is a painful discovery for the uninitiated.


For example: I created two partial views _First and _Second and each had this line added. The result :(



   X-Frame-Options: SAMEORIGIN, SAMEORIGIN



Bottom line: try to have just one reusable AntiforgeryToken per page. Technically speaking, one instance should be enough too. You should probably think again if you need more than one instance.


Monday 2 November 2015

Dictionary.Keys.ElementAt method is slow (C# fun)

So, we were extending one the earlier implementations and required to loop through the Keys of a dictionary and perform operations that could be run in parallel. The code was added like following:

sw.Reset();
            sw.Start();
            Parallel.For(0, dictA.Keys.Count, (i) => {
                int x = dictA.Keys.ElementAt(i);
            });
            sw.Stop();
            Console.WriteLine("Time elapsed:" + sw.ElapsedMilliseconds);


On the surface this does not look all that bad. If you run this against a dictionary that has 100000 keys, this takes about 6-7 seconds on my machine. Clearly, something is amiss.

Looking through the implementation of ElementAt provides insight into why it is slow.

If you change the method to following, you can see why I say ElementAt is slow in this case.

sw.Reset();
            sw.Start();
            Parallel.ForEach(dictA.Keys.ToList(), (i) => {
                int x = i;
            });
            sw.Stop();
            Console.WriteLine("Time elapsed:" + sw.ElapsedMilliseconds);

Here are the results.

Time elapsed:6218
Time elapsed:6

Sunday 1 November 2015

“ and " are not the same

Here is a nifty bit that can help folks who build user interfaces (web, desktop or mobile). We seldom build UI that does not have text boxes. Text boxes, single line or multi line, allow users to enter details that are best suited as free text.

If you are a .NET developer then you would most probably be using DataAnnotation attributes on model properties that are bound with the UI elements. In case of free text, we end up using a RegularExpression Validators to enable automatic validation of user input.

In this particular case, Regular Expression is a white list of characters. And here is a catch. We end up creating regular expression using the characters typed on Visual Studio Text Editor which leaves out certain similar valid characters, mainly because they are not supported on the editor. Microsoft Word is one such case where the typed content is not same as similar content typed on notepad and therefore can cause unwanted behavior in system.

My colleague (Amit) helped me in figuring out the difference in character codes for the characters which look identical on surface.


Char Code Of : 8211
Char Code Of ` : 8216
Char Code Of : 8217
Char Code Of : 8220
Char Code Of : 8221

Char Code Of - : 45
Char Code Of ' : 39
Char Code Of ' : 39
Char Code Of " : 34
Char Code Of " : 34

So, next time onwards, when you create regular expression, think if you need to support content typed on or copied from MS word :)