IoC and the Dependency Inversion Principle (DIP)

 

A couple of weeks a go a colleague of mine who was in the first week of a new project asked me "Which inversion of control (IoC) framework should I use?", to which I flippantly replied "Write an abstraction layer so you don't care!". At this point another colleague who had been listening gave me one of those looks and said, "What?, write an abstraction layer on top of an abstraction layer, are you nuts!". At this point the conversation degenerated...

IoC containers are one of the latest “cool” new things in software development, and we all know how much we developers like “cool” new things and how hard we will work to find creative ways to implement them. This is emphasised by the fact that the question being asked was, which IoC framework should I use?, rather than what are the high level requirements? We also know, from experience that “cool” new things tend to have volatile APIs and capabilities for a while before they settle. During this period of volatility we also need to consider support, will the IoC container continue evolve and be supported?

Where should we use IoC containers?

We should use them where they will provide real benefit. Could everything in an application be accessed through an IoC container, probably..., should it, absolutely not, this smells of needless complexity. Try to take an incremental, test driven approach to development. Focus on creating maintainable solutions, whilst avoiding needless complexity. During initial increments the "new" operator may work just fine, as you progress it will become clear which classes have a lot of dependents and are subject to change, at this point you may abstract and refactor using Factory Pattern, and from the IoC. The point is, apply IoC when it is required, rather than wherever possible.

Which IoC container should I use?

I’m sticking to my guns on this one, the client shouldn’t care. By employing the Dependency Inversion Principle  (DIP), it is easy to remove any client dependencies.

Software consultant Robert C. Martin stated the DIP this way:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

Most software systems these days are organised into layers, the diagram below shows a naive implementation of a layered system and the its dependencies.

image

The problem with this approach is the dependency chain, changes to downstream components will affect their dependents. A solution to this is to invert the dependencies.

image

A more complete description can be found here The Dependency Inversion Principle

Now if we apply this principal to our IoC example:

image

The thing to remember here is that the diagram is showing how the dependencies should flow and does not necessarily imply an implementation. For example, the abstraction between the client and the service layer could be implemented as a simple static utility class, or utilise the Factory pattern, etc. The point is, there is no dependency on the IoC container.

Free Productivity Tools for Visual Studio

Got to see this in action at PDC and it looked pretty cool, it's also at my favourite price, i.e. free!!

http://blogs.msdn.com/charlie/archive/2008/10/29/coderush-xpress-for-c.aspx

Delegates Gotcha
Hit a small gotcha today whilst using delegates. Take a look at the following (contrived) example...
   1: public delegate object Getter();
   2:  
   3: public interface ITest
   4: {
   5:     Getter Getter
   6:     {
   7:         get;
   8:     }
   9: }
  10:  
  11: public class Test : ITest
  12: {
  13:     private object GetValue()
  14:     {
  15:         //    implementation....
  16:     }
  17:  
  18:     #region ITest Members
  19:  
  20:     public Getter Getter
  21:     {
  22:         get { return GetValue;  }
  23:     }
  24:  
  25:     #endregion
  26: }

 

If you examine the code you will spot the implementation of ITest.Getter returns a delegate pointing to the GetValue method. The code doesn't appear to be very complicated, surely not much is happening here? Well, not much, but enough to severally hit performance in my case. The thing is, this line of code results in the compiler creating and returning a delegate each and every time this property is accessed. This would be obvious if the compiler forced you to write "new Getter(GetValue)", however, since .NET 2.0 it doesn't. The simple fix is to cache the delegate as shown below...

   1: public delegate object Getter();
   2:  
   3: public interface ITest
   4: {
   5:     Getter Getter
   6:     {
   7:         get;
   8:     }
   9: }
  10:  
  11: public class Test : ITest
  12: {
  13:     private Getter getter;
  14:  
  15:     public Test()
  16:     {
  17:         getter = GetValue;
  18:     }
  19:  
  20:     private object GetValue()
  21:     {
  22:         //    implementation....
  23:     }
  24:  
  25:     #region ITest Members
  26:  
  27:     public Getter Getter
  28:     {
  29:         get { return getter;  }
  30:     }
  31:  
  32:     #endregion
  33: }

This fix reducing the time taken for an operation to run from 15 seconds down to 2 in something I was working on!!

Insert Code Snippet Plug-In for Live Writer

Unfortunately there are a few "Insert Code" plug-ins available live writer, some better than others (I was previously using the not so good one :( ). To save others the hassle of trying lots of different ones here is my recommendation http://gallery.live.com/liveItemDetail.aspx?li=d4409446-af7f-42ec-aa20-78aa5bac4748&bt=9&pl=8 It provides syntax highlighting, line numbering and best of all allows the code to be placed in a scrollable container which prevents the text from going out of view.

How to use WSE 3 in Visual Studio 2008

The design time features of Web Service Enhancements 3 (WSE 3) are not officially supported for Visual Studio 2008. The only reason I can find for this is that Microsoft would prefer you migrate your code to WCF. Fair enough, some might say, WCF is a better technology, isn't it? Well, it depends on what you call better, if you've developed a working product for a client using WSE 3, how do you justify the expense of upgrading the solution to WCF? How also, do you justify the work required to your Smart Client Update implementation that will be required to roll out .NET 3.0 to their 20,000 clients? Will those clients accept .NET 3.0 on their machines, i.e. are they still running Windows 2000, or have a corporate policy that may prevent this? The point is, although updating the software may be easy, this is only one small part of the problem.

For those in the same predicament here is the solution (or at least some pointers on how to write one)...

WSE 3.0 adds its proxy classes to the code generated for a web reference through a standard extension mechanism employed by the ServiceDescriptionImporter class which is invoked by the MSDiscoCodeGenerator custom tool.

Extensions for the ServiceDescriptionImporter class are configured within the application configuration file. For Visual Studio this configuration file is named "devenv.exe.config" and can be found in the same location as the main Visual Studio executable.

Here is the configuration required to add the WSE3 extensions.

<system.web> 
    <webServices> 
        <soapExtensionImporterTypes> 
            <add type="Microsoft.Web.Services3.Description.WseExtensionImporter, 
Microsoft.Web.Services3, Version=3.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </soapExtensionImporterTypes> </webServices> </system.web>

NOTE: When editing the "devenv.exe.config" file under Windows Vista you should make sure you have elevated permissions. If you do not elevate you permissions the file will be saved transparently and without warning to a mapped virtual directory, i.e. not to the same location you opened it from.

The next step is slightly trickier...; although we have configured the extension, by default it will not generate any code. The reason for this is that the extension queries a delegate (assigned by the WSE Visual Studio Addin on Visual Studio 2005) to determine if WSE has been configured for the project.

public class WseExtensionImporter : SoapExtensionImporter
{
   public static WseExtensionImporter.IsWseReferencedInActiveProject 
      IsWseReferencedActiveProjectImplementation;
   public static WseExtensionImporter.IsWseReferenced 
      IsWseReferencedImplementation;
   public WseExtensionImporter();
   public override void ImportMethod(CodeAttributeDeclarationCollection metadata);
   public delegate bool IsWseReferenced(string rootNamespace);
   public delegate bool IsWseReferencedInActiveProject();
}   

To make the extension generate code we must attach an implementation to the IsWseReferencedInActiveProject property within the Visual Studio 2008 design environment. The easiest way to do this is to write a quick Addin using the Visual Studio 2008 Addin wizard. There are plenty of articles on how to do this elsewhere so I won't go into details.

Once the Addin wizard has completed, perform the following steps: 

  1. Add Microsoft.Web.Services3 and VSLangProj to your project references.
  2. Update the OnConnection method as follows:
public void OnConnection(object application, ext_ConnectMode connectMode,
   object addInInst, ref Array custom)
{
   _applicationObject = (DTE2)application;
   _addInInstance = (AddIn)addInInst;
         
   WseExtensionImporter.IsWseReferencedActiveProjectImplementation = delegate()
   {
      foreach (object activeProjectObj in (Array)_applicationObject.ActiveSolutionProjects)
      {
         Project project = activeProjectObj as Project;
         if (project == null)
            continue;

         VSProject vsProject = project.Object as VSProject;
         if (vsProject == null)
            continue;
               
         if (vsProject.References.Find("Microsoft.Web.Services3") != null)
            return true;
      }

      return false;
   };
}

3.   Install and activate the Addin.

WSE Proxies should now be generated for all projects that include Microsoft.Web.Services3 in their references!!!

Special Folders

One thing I like about the "Special" folders (Documents, Music, etc.) in windows Vista is that you can now move them to any location you like simply by cutting and pasting them. I move all folders in my profile to a separate drive where there is more space for large files (music & video) and I have the added comfort of knowing that most of my settings are safe if I decide to perform a re-install of the OS.

One gotcha in this process is permissions, for example moving your "Favourites" folder can result in Internet Explorer not being able to add favourites and the error can be a little cryptic, i.e. "Unspecified error..." To overcome this you will need to alter your permissions on the folder (the simplest method being to grant full control to Authenticated Users). Note: you may need to restart Internet Explorer for this to take effect.

Another gotcha I hit recently occurred when all the icons disappeared for my "Special" after I copied them to another drive for maintenance and then copied them back. The following link proved very useful in fixing this issue:

http://maxeasyguide.blogspot.com/2008/06/restore-default-folders-icon-in-vista.html

 

 

 

 

Virtualizing my Development Environment

One day my machine died L. It had been playing up for a little while and one day it just decided it wouldn't boot, the culprit seemed to be a dodgy hard disk.

At my company we use VMware Workstation to run test stacks on our local machines which we can develop against in isolation. Due to most of our development being targeted toward 32bit windows under Visual Studio 2008 we tend to use Vista 32 bit as our main OS. Our machines are fairly beefy with 4 GB of ram, however, we cannot fully utilise the 4 GB using 32bit Vista and whilst running VMs I'd ideally like 8 GB or more.

As I sat considering my imminent rebuild it occurred to me that I could install a 64bit OS and run my 32 bit development environment within a VM.

There seems to be several advantages to running my development environment within a VM.

  1. I could play around with new development tools, plug-ins, etc. software within a familiar environment without risk as I could easily rollback to a previous snapshot.

     

  2. Even if the worst happened and my VM got corrupted somehow I could be up and running quickly from backup (I realize this could be achieved with software such as Ghost or dd).

     

  3. I could place more memory in my machine (8 GB max in my current box) and take advantage of it whilst continuing to developer and test in 32bit environments.

My initial thinking was, if I could install a relatively lightweight host OS I should be able run more VMs. So it begins....

Configuration 1 – Kubuntu 8.04 64bit Host

First thing to state is that my personal preference when using Linux is to use the KDE desktop environment. It just seems feels slightly less patronising, allowing me to get the day to day tasks done quickly and easily without hiding away features I perhaps ought not to be trusted with J

The first host configuration I tried was Kubuntu 8.04 64bit. Kubuntu seemed to have performance issues running VMware 6.04 and also felt a little like the KDE had been slapped on as an afterthought, which may not be far from the truth as the main distribution "Ubuntu" is Gnome based.

I later found that the performance issues with VMware were related to a general Linux kernel/VMware version issues and were not specific to Kubuntu.

Configuration 2 – OpenSuse 11 Host

I then decided to try a KDE based distribution, and opted for OpenSuse 11 64bit. Installation went well; the whole thing was installed in about 20minutes including all recommended updates and the native NVIDIA drivers. One thing I particularly liked about OpenSuse was that it included the NVIDIA settings tool by default with the driver which made configuring multi-monitor a doddle (something that would be quite difficult for a novice in Kubuntu as the forums would have you doing all sorts of things to you xorg.conf file).

I then installed VMware, and experience similar, although not quite as bad issues with performance as before.

After trawling a few forums posts I got the impression there was a general issue with at least versions 6.03 and 6.04 of VMware with my kernel. The suggested option was to try VMware 6.5 beta, which I wanted to play with anyway due to the support for DirectX 9.0c and new integrated desktop features dubbed "Unity".

VMware 6.5 beta went on to my system without any problems, it was time to start running some VMs. And that's where the problems began...

When running more than one virtual machine my machine became almost completely unusable, the mouse would stop responding for a few seconds at a time and CPU utilisation was almost permanently at 100%. After running "top" I discovered that a large proportion of the CPU was being consumed waiting for IO to complete. So (sigh), back to the forums..., turns out that by default VMware performs background memory paging, which on my machine was murdering IO. Performance was significantly improved by adding the following lines to my .vmx file:

mainMem.useNamedFile = "FALSE"
sched.mem.pshare.enable = "FALSE"
MemTrimRate = "0"

Ok, I was now able to mount 3 guest VMs, a Vista Desktop, a 2003 Server with a complete TFS test stack, and another XP desktop just for good measure. Performance was great, I was really cooking on gas... that was, until I decided to switch back to my host and do some web browsing. I launched Firefox and started to type in the address bar, Firefox closed abruptly without any warnings or messages, I tried again, same thing, and then again, need I continue? It was at this point that I noticed that I couldn't type any upper case characters, my shift and caps lock keys were not working! At this point my head hit the desk L

After removing the ice pack, I gritted my teeth in grim determination for my imminent return to the forums.

It seems the crashes are related to two bugs, one being VMware workstation clearing the keyboard modifier map, the other being the GTK crashing when it encounters and empty modifier list (This has reportedly now been fixed). The VMware issue seems to have been around for some time, I have tracked it back to at least version 5 in the forums, so it doesn't appear that this is going to get fixed any time soon (VMware?).

To prevent VMware from clearing the keyboard modifier map you should switch back to your host using the mouse rather than the keyboard (Ctrl + Alt by default). If on returning to your host you find you caps lock indicator is not working you can re-initialise you keyboard by running the following command:

setxkbmap

I continued to try and work this way for a while, mainly out of sheer stubbornness and reluctance to admit things weren't working out as well as I had planned. I also didn't want to spend any more time in the forums or installing software, I'm a developer with a job to do (write code); I lost interest in hacking around installing software back in my Amiga days (pauses to reminisce).

Finally I gave up, I really couldn't live with the keyboard issue and I certainly wasn't going to run a scheduled task to reset my keyboard modifiers every n seconds as some had suggested (argh!!!).

I decided to try Vista 64bit.

Configuration 3 – Vista Enterprise 64bit

I almost wish I had more to say here. The installation of Vista Enterprise 64bit and VMware 6.5 beta went without issue. I fired up my VMs and have been running them successfully for about a week.

I should point out at this stage that the changes I made to .vmx files to prevent paging were kept and I haven't gotten around to proving whether the performance issues I encountered without them would show up under Vista.

Vista does by default consume a lot more memory than any of the Linux distributions I tried, although I'm sure I could get this down a bit with some tweaking of services, etc.

Conclusion

I really wanted this to work easily under Linux, "easily" being the key word here. I've no doubt that with time I could have resolved all the issues I encountered, however, there is a finite amount of time you can spend on these things, after all, time is money. I was also getting tired of defending Linux to my colleagues, as they fell about laughing every time I swore at it.

Linux did seem to utilise resources better, a default installation could run more VMs due to its default low memory footprint.

It also turned out that going the Vista route did not involve buying any additional Vista licences as my company has Vista Enterprise licences under the gold partner program which means we can run a Vista host and several guests under one licence.

Additional

During my adventures on Linux I did also try VirtualBox. I've tried VirtualBox before and I have to say it's one of the easiest virtualization platforms I've come across to install and use. It supports snapshots, integrated desktop, VMs run very fast and best of all its OpenSource, i.e. free.

In spite of this there are numerous reasons (depending on your needs) for chosing VMware:

  • VirtualBox does not have as yet multi monitor support.
  • VirtualBox does not utilise memory as efficiently as VMware, its lazy loading does not appear to be that lazy, and it does not page share.
  • VirtualBox has no DirectX support (not that important for most scenarios, but worth a mention).

At some point I may try xen...

Automated Exploratory Testing

I've just been sent a link from one of my colleagues to a Microsoft research project looking into automated exploratory unit testing. Check it out, looks very interesting http://research.microsoft.com/pex/

VMWare Server on Vista

VMWare Server on Vista up to release 1.03 seems to lock the entire machine during start-up of a VM, once the VM is started the system usually returns to normal, but this can take a few minutes during which time the machine is unusable.

After some forum investigation I found no solution but a reference to the VMWare Authorisation service as the culprit. I took a look through the "VMWare\VMWare Server" folder and found a command called vmware-authtrusted.exe (sounded like it had something to do with authorisation) . I ran this, entered my domain credentials and checked the trusted option, I then fired up a VM good news!!! Everything is performing in a pre-vista fashion, i.e. fast...

 

Mnemonic Demonics in MDI applications

It seems that the key mnemonics implementation in .NET for MDI applications can cause some undesirable side effcects. For anyone that isn't familiar with the term, Key mnemonics are the short cut keys on buttons, labels etc. usually shown as underbars and usually activated using an ALT+KEY combination.

To demonstrate the behaviour exhibited by MDI mnemonics imagine the following scenario. You have an MDI application with two MDI child forms open, one for displaying a list of customer records and another for adding new order details. The customer MDI child form contains a button for deleting the current customer record which has a mnemonic on the 'D' character.

Now, imagine that you are happily typing away in you new order details form, you have just tabbed off the last edit box onto the "Accept Changes" button when you accidentally hit the 'D' key. Even though the form showing the list of customers is not active you are surprised to see the application is prompting you to confirm a delete operation!!!

Note: if you have the "Hide underlined letters for keyboard navigation until I press the Alt key" checked in windows you must press "ALT+D" for this affect to be noticed.

At this point I think it worth mentioning a few points:

1.   MDI applications are not generally considered good design, I remember reading Microsoft guidelines several years ago which warned against their use (I'll try and dig this out).

2.   MDI child forms are not dialogs, and in my opinion should not really contain buttons. Buttons/actions for MDI children should be hosted on a context sensitive toolbar which updates its options depending on which form is active.

Ok, that said how do we fix the issue?

Method 1:

overriding the ProcessMnemonic method on each MDI child form, the code is pretty self explanatory.

protected override bool ProcessMnemonic(char charCode)
{
   if (this.MdiParent != null)
   {
      return MdiParent.ActiveMdiChild == this && base.ProcessMnemonic(charCode);
   }
   else
   {
      return base.ProcessMnemonic(charCode);
   }
}


Method 2:

Override the ProcessMnemonic on the MDI parent form.

The MDI container form always receives the original ProcessMnemonic message. The default .NET implementation then iterates forwards through all controls starting with the active control until it finds a control that will process the mnemonic. In our solution we also need to iterate through all controls, however, we need to skip any MDI children that are not active. Unfortunately the ProcessMnemonic method is protected (Why!!) so we must use reflection to forward our ProcessMnemonic calls.


      private System.Reflection.MethodInfo processMnemonicMethod;

      public MyForm()
      {
         processMnemonicMethod = typeof(Control).GetMethod("ProcessMnemonic",
            BindingFlags.Instance | BindingFlags.NonPublic);
      }
     
      protected bool CallProcessMnemonic(Control control, char charCode)
      {
         if (processMnemonicMethod = null)
         {
            return (bool)processMnemonicMethod.Invoke(control, new object[] {charCode});
         }
         return false;
      }

      protected override bool ProcessMnemonic(char charCode)
      {
         if (base.Controls.Count != 0)
         {
            Control control1 = this.ActiveControl;
            while ((control1 is ContainerControl) && (((ContainerControl) control1).ActiveControl != null))
            {
               control1 = ((ContainerControl) control1).ActiveControl;
            }
            bool flag1 = false;
            Control control2 = control1;
            do
            {
               control2 = base.GetNextControl(control2, true);
               if (IsMdiContainer)
               {
                  Form form = control2 as Form;
                  if (form != null && form.MdiParent == this && this.ActiveMdiChild != form)
                  {
                     continue;
                  }
               }
               if (control2 != null)
               {
                  if (CallProcessMnemonic(control2, charCode))
                  {
                     return true;
                  }
               }
               else
               {
                  if (flag1)
                  {
                     break;
                  }
                  flag1 = true;
               }
            }
            while (control2 != control1);
         }
         return false;
      }

Personally I would recommend the first approach; it has a cleaner feel (not requiring reflection) and more granular control.