Sunday 31 May 2015

In the world of VB6

If you ever get an assignment where you are asked to migrate or rewrite an existing VB6 code base, then keep the following things in mind:

Arithmetic operations differ between .NET and VB6

Yep. If you have a code like below in VB6 then you need to be careful:

x  = y/12

If y is 1 then x is 0.083333 in VB6. If you run the same code in .NET, it is 0. To get parity between the two you will need to use following in .NET

x = y/12.0


Tool based migrated code isn't the best code

Let us accept that VB6 code was generally written to best utilize the capabilities available at the time when the code was written. World has changed then but companies did not spend money on changing their code - they are generally forced to change the old (legacy) code when some sort of support is going off. Then comes the usage of some sort of migration tools. There are plenty of good tools available in market which can migrate an existing VB6 code to .NET with high level of accuracy (they never claim 100% accuracy). So your real trouble starts when you try to work with the code migrated by a tool which is partially accurate :).

What is more interesting is that such code bases (which were written in VB6 a few decades ago and maintained since then), would not have any type of unit tests which you can use to confirm if the migrated code is correct.

Continue on Error

This was a killer feature in VB6 language. You work with some data and you get an exception - you tell the program to not bother about the exception and move on the next set of activities. This was extremely useful in cases where you needed to process set of records fetched from database or file.

When you migrate to .NET, you would cringe for such feature. The best way to match that logic (of course you can not force a business to change its core logic because they are changing from VB6 to .NET) is to catch and suppress exceptions for each record so that you can keep moving forward.

VB6 is generally faster

Yeah. It is kind of true. At least it would feel like that.

VB6 is 32 bit

And this would mean if your legacy code base has an existing component which does not have its source code (Yes, it is true. I have met such customers.) then you would have only 2 choices - keep migrated .NET application as x86 application or wrap that component logic in a separate 32 bit process and keep remaining application as 64 bit. That would mean one serious issue - latency and one additional application to maintain. You can speed it up by hosting it existing DLL in a WCF service behind net.pipe binding but it can never beat in-process calls.

Sunday 3 May 2015

Bulk "Add Reference"

My team works on a large solution and there was an interesting situation where needed to add a common reference across about 90 odd projects in the solution. There isn't a straightforward way to do that in Visual Studio yet. So, what do we do? We write a simple program, isn't it. In the end, all references go to csproj projects and csproj file is a relatively simple and human readable text file.


string directoryPath = @"D:\solutionLocation";
            DirectoryInfo dirInfo2 = new DirectoryInfo(directoryPath);
            foreach (var file in dirInfo2.GetFiles("*.csproj", SearchOption.AllDirectories))
            {
                var lines = File.ReadAllLines(file.FullName);
                for(int i = 0; i < lines.Length; i ++)
                {
                    if (lines[i].Contains("Reference Include=\"System\""))
                    {
                        lines[i] = @"False..\References\Newtonsoft.Json.dll";
                    }
                }

                File.WriteAllLines(file.FullName, lines);
            }
           

For this to work effectively against TFS, you should create a local workspace so that any file save is automatically detected as a checked-out item and starts to show up in Pending Changes window. If you use Server workspace, performance of TFS operations (get, merge etc.) may improve but you lose the feature of automatic detection of file changes.

A poor man's solution but it works.

Performance improvements in JSON serialization

Last week I wrote a post about why Newtonsoft.JSON should be the undisputed choices when dealing with JSON serialization operations. However I ran into some interesting scenarios :). These scenarios do not indicate the there is an issue with NewtonSoft.JSON - they indicate that we should be using it with correct configurations.

1. We use PostSharp to instrument the assembly to inject Trace statements during compilation. The AOP implementation serialized all the parameters (JSON format) and logged in database. What was interesting was that the implementation was supplied with parameters of type like FileStream, NetworkStream, MemoryStream etc. for serialization. Now that is problematic because you do not want to read stream content in the method because that may lead to unwanted side effects. Newtonsoft.JSON does provide us a way to handle that though. 

We can use "JsonSerializerSettings" class to indicate the custom Errorhandler in case serialization fails something that is true for streams. However, that would mean the application flow will need to go through exception handling process unnecessarily and will slow down the logging process. Good news is that Newtonsoft.JSON comes with a ContractResolver option where we can filter out properties (based on their type) and not log those. That solves the problem to some extent.

        var JsonSerializerSettings serializationSettings = new JsonSerializerSettings()
        {
            Error = (s, e) => { e.ErrorContext.Handled = true; },
            ContractResolver = new CustomResolver()
        };

        
2. Now, I have 2 options to serialize the argument collection.

a. Simply serialize the collection directly:

JsonConvert.SerializeObject(items, settings);

b. Loop through items in argument collection, serialize them individually:

public static string ToString(IEnumerable<object> items)

{
            StringBuilder builder = new StringBuilder();
var JsonSerializerSettings settings = new JsonSerializerSettings()
        {
            Error = (s, e) => { e.ErrorContext.Handled = true; },
            ContractResolver = new CustomResolver()
        };

foreach (object argument in items)
            {
               builder.AppendLine(Newtonsoft.Json.JsonConvert.SerializeObject(argument, serializationSettings));
            }
    return builder.ToString();
}

Option b worked better for me. YMMV though :)

3. There was one problem though - performance. 

I wrote a simple test that loops through the ToString function 100,000 times and it took ~62 seconds to complete. 0.6 ms for each iteration, not bad!! 

List arguments = new List();
            arguments.Add(new MemoryStream());
            arguments.Add(1);
            arguments.Add("ioeitosdnksdsd");
            TestClass c = new TestClass()
            {
                MyProperty = 1,
                MyProperty2 = new MemoryStream()
            };
            
            Stopwatch w = new Stopwatch();
            w.Start();
            for (int x = 0; x < 100000; x++)
            {
                var serializationSettings = new JsonSerializerSettings()
                {
                    Error = (s, e) => { e.ErrorContext.Handled = true; },
                    ContractResolver = new CustomResolver()
                };

                StringBuilder argumentBuilder = new StringBuilder();
                foreach (object argument1 in arguments)
                {
                   builder.AppendLine(Newtonsoft.Json.JsonConvert.SerializeObject(argument, serializationSettings));
                }
            }
            w.Stop();
            Console.WriteLine(w.ElapsedMilliseconds);
            Console.ReadLine();
            return;

That was not enough actually. This particular method that we wrote was expected to be used heavily as we have extensive logging in the application. During our load testing, we found out that it can lead to queuing of requests on IIS. 

Let us see if something can be done in this regard. Actually, yes. The serializationSettings instance is not needed to be created everytime because it can be reused for each operation. Move it outside the loop.

List arguments = new List();
            arguments.Add(new MemoryStream());
            arguments.Add(1);
            arguments.Add("ioeitosdnksdsd");
            TestClass c = new TestClass()
            {
                MyProperty = 1,
                MyProperty2 = new MemoryStream()
            };
             var serializationSettings = new JsonSerializerSettings()
                {
                    Error = (s, e) => { e.ErrorContext.Handled = true; },
                    ContractResolver = new CustomResolver()
                };
            Stopwatch w = new Stopwatch();
            w.Start();
            for (int x = 0; x < 100000; x++)
            {
               StringBuilder argumentBuilder = new StringBuilder();
                foreach (object argument1 in arguments)
                {
                   builder.AppendLine(Newtonsoft.Json.JsonConvert.SerializeObject(argument, serializationSettings));
                }
            }
            w.Stop();
            Console.WriteLine(w.ElapsedMilliseconds);
            Console.ReadLine();
            return;

Total time is 171 milliseconds now. Whoa!!