I don't want to be a wet blanket, but someone's got to put a stop to the IoC love fest going on out there.  An Inversion of Control (IoC) container , for those of you were aren't yet familiar, allows you to retrieve instances of objects at runtime.  A relatively common solution to a common problem. In the .NET world there is no lack of choices of IoC containers:

(I won't go fully into IoC, but If you'd like more resource you can read Martin Fowler's article on the subject or post specific questions in the comments or contact me through.  Read on, there is value here in this post for you.)

Let me state clearly now, IoC containers are a means to an end and NOT a feature of your application. The goal is to have loosely coupled applications, IoC containers help get you there, but you can absolutely have a loosely coupled application without an IoC container (see the Gang of Four creational patterns).

Occasionally I'll hear some comment about IoC and how great a certain container is or how an application would be so much better if another, sexier, container was used.  Here are some recent tweets that illustrate:

  • Man i love #StructureMap, always finding new things i can do, and have fun doing them
  • really need to look at structuremap, but we''ve invested a lot into castle with our own facilities/resolvers/etc
  • Ninject is da bomb!
  • Switched from Windsor MicroKernel to Ninject in 10KLOC project in < 1 hour by creating a little proxy. Now to complete the conversion.
  • It is a talk on Castle Windsor so i guess Ninject will not do.
  • Can't imagine why somebody would use Ninject beside the fact that it's PURE AND UTTER AWESOME. Yeah! Ninject FTW.

Some of the statements above are probably innocuous, but some rub me slightly the wrong way.  Specifically the two comments above about switching from one container to another. There are probably times when the choice of one container over another makes sense, but I would bet that these scenarios are the exception and not the rule.

Choosing one container over another won't make your application a success, the architecture, or lack there of, will have far more of a say on your application than will your container choice. As yoda might say, "The container you choose does not a good app make".


 
Categories: IoC | Rant | Tools | Windsor

Shhh...don't tell anyone but we don't unit test all of our code.  We're striving to get all developers and managers on board with unit testing but we're not there yet.  Despite our delinquency in writing tests one thing we do try our very best to do is keep mistakes from happening again.  If we find a bug in the system, before fixing it, we go and write a unit test for that problem.  We verify the test fails, the go and write the code that fixes it.  This recognizes that bugs will appear in the system, but once fixed we'll insulate ourselves from that bug happening again.

We had one such case last week.  We were getting a yellow-screen error after a bunch of commits by developers.  The error stemmed from a component in Windsor that did not have all of it's dependencies met.  In other words, we registered a component which relied on another component which was not registered.  We already had written a test to compile and test our Windsor configuration, however that test was not mature enough and needed some tweaking. 

In our application we leverage the new ASP.Net MVC.  We also take advantage of the ability to leverage an IoC container, Windsor, to create controller instances when a web request comes in.  When the application starts, we register all of the controllers in the application into Windsor using reflection.  Therefore our Windsor configuration at runtime is made up of two things, the XML configuration and the controllers which are registered on startup.  The "bug" here was that one of our controllers had a dependency on it that was not registered in Windsor.  When you ran the test by itself, the test would pass, since it was only loading up the components from the Windsor configuration.

Wanting to protect us in the future, we acknowledged there was something missing from our test and set out to find it.  To create the failing test was relatively simple.  All that we needed to do replicate in our test what we were doing at runtime.  Therefore we needed to register all implementers of IController, just like we do on application startup.  Below I've

Before:

   1: IWindsorContainer container = new WindsorContainer("windsor.config.xml");
   2:  
   3: foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
   4: {
   5:     Console.WriteLine("{0}\n\t- {1}", handler.ComponentModel.Service, handler.ComponentModel.Implementation);
   6:     container.Resolve(handler.ComponentModel.Service);
   7: }

After:

   1: IWindsorContainer container = new WindsorContainer("windsor.config.xml");
   2:  
   3: var assm = new HomeController(null).GetType().Assembly;
   4: //add all controllers
   5: foreach (Type type in assm.GetTypes())
   6: {
   7:     if (typeof(IController).IsAssignableFrom(type) && !type.IsAbstract)
   8:     {
   9:         container.AddComponent(type.Name.ToLower(), type);
  10:     }
  11: }
  12:  
  13: foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
  14: {
  15:     Console.WriteLine("{0}\n\t- {1}", handler.ComponentModel.Service, handler.ComponentModel.Implementation);
  16:     container.Resolve(handler.ComponentModel.Service);
  17: }

Now that this test is in place, I am much more confident that we won't see the error we were seeing in product again, we've got a test which warns us if something isn't quite right.  Our initial test didn't quite get it all right.  Mistakes/bugs in code will happen, hopefully few and far between, but when a bug does show up, go write a test that verifies the bug before going off an fixing it.  Then make the test pass, which should fix the bug.


 
Categories: ASP.NET MVC Framework | Caslte | Testing | Windsor