Sunday 29 March 2015

IE9: cloneNode issue

Apparently the cloneNode method gets executed in an undesirable way on IE9. You may ask why am I stuck with IE9 which in itself is a very valid question and worthy of a long discussion. However, let us stick to the original discussion for now.

My colleague and I recently did a pretty simple and innocuous implementation of PrintPreview functionality for a web application. Since we wanted to use Media Queries and other cool stuff, it made sense to implement it on JavaScript code.

  1. Clone the content of page using cloneNode function like "var body = window.document.body.cloneNode(true);"
  2. Create a new pop up window and load the cloned content in the new window.
  3. Apply media query related to Print style to ensure that print page shows up properly e.g. sidenav elements are hidden etc.

Everything worked like charm till we kept testing the implementation in Chrome, FireFox, IE11 and IE10. We did not care to test on IE9 :(. One of the test folks reported that the print preview pop up comes up as blank screen.

Interesting!! After enabling the F12 tools on IE9 (which in itself seems ancient tool now), we figured that pop up seems to execute the full page load (including network calls referred JS and CSS files). Since we had added some code in our JavaScript files that executed code on script load, it got executed in the pop up window too. Funnily, if you closed the popup and opened it again through our JS function, it increased the network calls in geometric progression fashion. Basically it was leaking resources. Consequently, after 2-3 attempts of script execution, the web page was busy in executing scripts and network calls and hence the page was blank :).

Fix:
1. Get rid of IE9. Not possible for many of us.
2. Fix the code. Remove anything that may have script inside the element before writing to the pop up window's document element. Since the pop up window was to support print preview functionality, we did not need those script features anyways. Below code snippet shows our approach for body tag - similar code had to be written for head tag too.

            var body = $(document.querySelector('body').innerHTML);
            $(body).find('script').remove();
            var popupWin = window.open('', 'Test', "width=1024,height=768,menubar=no"); 
            $(body).each(function () {
                if (this.outerHTML != undefined && this.tagName != "SCRIPT") {
                    popupWin.document.write(this.outerHTML);
                }
            });


Searching around the Internet reveals that others (Link # 1, Link # 2) did hit the same issue too and came up with their own workarounds :).

XML Serialization - Performance issue and Memory Leak

There are well documented issues with the XmlSerializer class that can cause performance issues along with memory leaks. Just in case you have not read about those, try these - Link # 1, Link # 2, Link # 3. The issue is related to the constructors that let you specify "Base Type" and list of "Derived Type". We had a requirement where we needed to store and retrieve data related to classes that have similar inheritance. e.g.

    public class BaseLog
    {
        public string Number0 { get; set; }
    }

    public class Log : BaseLog
    {
        public string Number { get; set; }
    }

    public class Log1 : BaseLog
    {
        public string Number1 { get; set; }
    }

    public class Log2 : BaseLog
    {
        public string Number2 { get; set; }

    }

To de-serialize the xml into appropriate type, we wrote a helper method:
public static TActualType Deserialize(string xml, Type[] derivedTypes)
        {
            TextReader reader = null;
            try
            {
                reader = new StringReader(xml);

                using (var xmlReader = XmlReader.Create(reader))
                {
                    reader = null;
                    XmlSerializer xmlserializer = new XmlSerializer(typeof(TBaseType), derivedTypes);
                    return (TActualType)xmlserializer.Deserialize(xmlReader);
                }
            }
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
            }

        }

The highlighted line started to show signs of memory leak and slow performance when started to load test our application. I wrote a simple console application that runs the serialization and de-serialization operation 100 times and ran it with Visual Studio's Memory Profiler. Results were scary :)

            int counter = 0, limit = 100;
            Stopwatch stopWatch = new Stopwatch();
            if (true)
            {
                counter = 0;
                stopWatch.Reset();
                stopWatch.Start();
                Console.WriteLine("Xml Serializer : No Cache");
                while (true)
                {
                    if (counter > limit)
                    {
                        break;
                    }

                    SerializeTest2(); // calls serialize/deserialize
                    counter++;
                }

                stopWatch.Stop();
                Console.WriteLine(stopWatch.ElapsedMilliseconds);

            }

private static void SerializeTest2()
        {
            Log a = new Log();
            a.Number0 = "PQR";
            a.Number = "ABC";
            var result = XmlSerializationHelper2.SerializeToXml(a);

            Log1 b = new Log1();
            b.Number0 = "PQR";
            b.Number1 = "ABC";
            var result1 = XmlSerializationHelper2.SerializeToXml(b);

            Log2 c = new Log2();
            c.Number0 = "PQR";
            c.Number2 = "ABC";
            var result2 = XmlSerializationHelper2.SerializeToXml(c);

            BaseLog d = new BaseLog();
            d.Number0 = "PQR";
            var result3 = XmlSerializationHelper2.SerializeToXml(d);

            BaseLog results = XmlSerializationHelper2.Deserialize(result, new Type[] { typeof(Log), typeof(Log1), typeof(Log2) });

            BaseLog results1 = XmlSerializationHelper2.Deserialize(result1, new Type[] { typeof(Log), typeof(Log1), typeof(Log2) });

            BaseLog results2 = XmlSerializationHelper2.Deserialize(result2, new Type[] { typeof(Log), typeof(Log1), typeof(Log2) });

            BaseLog resultss = XmlSerializationHelper2.Deserialize(result);

            BaseLog resultss1 = XmlSerializationHelper2.Deserialize(result1);

            BaseLog resultss2 = XmlSerializationHelper2.Deserialize(result2);

            BaseLog results3 = XmlSerializationHelper2.Deserialize(result3);

        }

It took ~6 seconds to run 100 loops and memory usage kept increasing with each iteration of the loop. The reason for this is documented (and I repeat): dynamic assembly generation - assemblies can not be unloaded unless you unload an appdomain and therefore the allocated memory keeps increasing. It was so bad that our application would start to throw "Out of Memory" exception whenever it had to deal with large number of records (read in excess of 1000 records). Below is the graph:




Solutions:
1. Cache the XmlSerializer instances. I added a pretty simple caching logic like below:
        private static Dictionary xmlSerializerDictionary = new Dictionary();


        private static object syncRoot = new object();

        private static string GetKey(Type type, Type[] derivedTypes)
        {
            StringBuilder builder = new StringBuilder();
            if (derivedTypes != null)
            {
                foreach (var derivedType in derivedTypes)
                {
                    builder.AppendFormat("{0},", derivedType.FullName);
                }
            }

            return string.Format("{0}_{1}", type == null ? string.Empty : type.FullName, builder.ToString());
        }

        private static XmlSerializer GetSerializer(Type baseType, Type[] derivedTypes)
        {
            string key = GetKey(baseType, derivedTypes);

            XmlSerializer xmlserializer = null;
            lock (syncRoot)
            {
                if (xmlSerializerDictionary.ContainsKey(key))
                {
                    xmlserializer = xmlSerializerDictionary[key];
                }
                else
                {
                    xmlserializer = new XmlSerializer(baseType, derivedTypes);
                    xmlSerializerDictionary.Add(key, xmlserializer);
                }
            }

            return xmlserializer;

        }

After the change, the same program took ~120 milliseconds :O and memory usage was flat and total memory usage came down significantly:



2. Forget about the XmlSerializer usage if you can :). There can be cases where JSON serialization can be handy too and its performance is as good as any other dependable implementation. You can use Newtonsoft.Json and use a simple implementation that lets you serialize and deserialize base class and derived class.

public static class JsonSerializationHelper
    {
        public static string Serialize(T obj)
        {
            return JsonConvert.SerializeObject(obj, typeof(T), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
        }

        public static T Deserialize(string content)
        {
            return JsonConvert.DeserializeObject(content, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
        }

    }

Running the same test against this implemention produces good results. It took ~250 milliseconds.


Thursday 26 March 2015

Projects have recently been added to this solution. Really?

One of the most dreaded things that one may be asked to do is to merge code base present in two different branches. Even though there are many amazing version control systems are available at our disposal e.g. Team Foundation Server, Git etc., merging conflicts during the merge becomes a true pain point. Add to that the misery of the fact that it might just break the build or say add unintended lines to the code base. 

Recently I took up the responsibility of merging two branches (because others did not want to do it, you know), I ran into an interesting merge case. If your code base is built using Visual Studio, there can be large solution files (.sln) which have cryptic GUID values that map to different sections and carry different settings. After merging code during last week, the target branch code started to show me strange popup "Projects have recently been added to this solution. Do you want to get them from source control?".


This was strange because there was no new project added to the source branch or target branch since the last merge. So i looked at the solution file (.sln) that was created after the merge. After going through it for some time, i figured out the culprit - solution file was somehow injected with multiple "GlobalSection(TeamFoundationVersionControl) = preSolution" sections during the merge. This caused the visual studio to expect more projects and thus the prompt.

Once i removed the spurious entries, it was normal again :)

Saturday 14 March 2015

Folder and File comparison using TFS

Team Foundation Server (TFS) has had a very nifty feature that is generally underutilized. "Compare" feature. Compare feature does exactly what it spells - it lets you compare two files or folders, both Server version and Local version.


There are many good usage scenarios for this feature:

1. Compare files files which are not in TFS. You do not need an additional compare utility if you have TFS client.
2. Compare folders which are not in TFS.
3. Compare local folders with folder present in TFS.
4. Compare folders that are present in TFS. I find it quite handy when I want to compare two TFS branches to find out if merge operation between the two is as expected. And of course, it lets you compare multiple files in two folders using filters.