REQUEST A DEMO

Creating a simple Windsor facility

Update: What this facility accomplishes is easily done using property setter injection in Windsor. Please use this post only as an example for creating a basic, yet misguided, facility.

Windsor is an excellent inversion of control (IoC) container. Besides putting components into the container for use with dependency injection you can extend, customize, tweak, spindle, the behaviors of the container by adding facilities. Facilities expose events and information about what is going on with the container such as what is being added to it and what objects are being created by it. This viewport into the container lets you inject behavior into the lifecycle of objects springing forth from the container. All of this at first is very confusing but lends itself to powerful capabilities.

The exercise I went through was to provide a TimeService as an aspect of our application. Normally developers use DateTime.Now to simply pull time from the system clock. This tends to be very difficult to test. By getting systemtime from mechanism under our control we can better control during tests what our TimeService will emit using mocks. For everyday usage I will rely on this new facility in the container to provide the TimeService.

TimeServiceFacility

The TimeServiceFacility works by detecting if a class being constructed by the container has a property called “TimeService” that returns a ITimeService. Here is a test that illustrates how the facility gets used

   [TestFixture]
   public class TimeServiceFacilityTests
   {
      public class HasTimeServiceProperty
      {
         private ITimeService _timeService;

         public ITimeService TimeService
         {
            get { return _timeService; }
            set { _timeService = value; }
         }
      }

      [Test]
      public void The_TimeServiceFacility_should_set_the_TimeService_property_for_components_that_have_a_ITimeService_property()
      {
         WindsorContainer container = new WindsorContainer(new XmlInterpreter(new ConfigResource()));
         TimeServiceFacility timeServiceFacility = new TimeServiceFacility();
         container.AddFacility("timeServiceFacility", timeServiceFacility);
         container.AddComponent("hasTimeServiceProperty", typeof(HasTimeServiceProperty));

         HasTimeServiceProperty hasTimeServiceProperty = container.Resolve();

         hasTimeServiceProperty.TimeService.ShouldNotBeNull();
      }
   }

To implement this we just need to create a facility that subclasses AbstractFacility and asks to be notified of new ComponentModels being created. If the type of the component being put into the container has the property we are looking we add a lifecycle step to the commissioning of new instances of the component type.

   public class TimeServiceFacility : AbstractFacility
   {
      private TimeServiceConcern _timeServiceConcern;

      protected override void Init()
      {
         _timeServiceConcern = new TimeServiceConcern();

         Kernel.ComponentModelCreated += new ComponentModelDelegate(OnComponentModelCreated);
      }

      private void OnComponentModelCreated(ComponentModel model)
      {
         if (IsWritableTimeServicePropertyPresent(model.Implementation))
         {
            model.LifecycleSteps.Add(LifecycleStepType.Commission, _timeServiceConcern);
         }
      }

      private static bool IsWritableTimeServicePropertyPresent(Type type)
      {
         return TimeServiceConcern.GetWriteableTimeServiceProperty(type) != null;
      }
   }

The life cycle step, ILifecycleConcern, simply grabs the TimeService property off the Type of the component and uses reflection to set the property’s value to a new plain TimeService.

   public class TimeServiceConcern : ILifecycleConcern
   {
      public static readonly string TimeServicePropertyName = "TimeService";

      public void Apply(ComponentModel model, object component)
      {
         PropertyInfo propertyInfo = GetWriteableTimeServiceProperty(model.Implementation);

         if (propertyInfo != null)
         {
            propertyInfo.SetValue(component, new TimeService(), null);
         }
      }

      public static PropertyInfo GetWriteableTimeServiceProperty(Type componentType)
      {
         PropertyInfo propertyInfo = componentType.GetProperty(TimeServicePropertyName, typeof(ITimeService));

         if (propertyInfo == null || propertyInfo.CanWrite == false)
         {
            return null;
         }

         return propertyInfo;
      }
   }

The TimeService is not exciting and simply there to be replaced during testing if necessary.

   public class TimeService : ITimeService
   {
      public DateTime GetSystemTime()
      {
         return DateTime.Now;
      }
   }

Navel Gazing

If you are familiar with IoC you may be asking yourself why we didn’t simply pass the ITimeService into the constructor of the objects that need them. We felt that the TimeService was more of an aspect of the system. If you need a timestamp you add TimeService property. To avoid code duplication regarding implementation of the TimeService property we could put the property into a base class or possibly use a C# 3.0 extension. Not sure how this will pan out.