Switching component implementations in Castle Windsor
Problem: Test suite for a system for which I need to replace (inject) the behavior of a certain component. The system is using Castle Windsor with an XML configuration file.
In this system integration test I want to use the real container configuration except that I want to switch out a component that does authorization using a database.
The replacement for the real component is as simple as:
public bool IUsernamePasswordVerifier.VerifyPasswordFor( string username, string password ){ return true;}
Solution: Tried this, which failed on me. But with a little help from a tiny facility used by the test suite I can now “re-wire” service implementations in the container.
There are probably several other solutions on how one could accomplish the same thing, but this one worked out very well for me.
ComponentRewriterFacility.cs:
using System;using System.Collections.Generic;using Castle.Core;using Castle.Core.Configuration;using Castle.MicroKernel;
namespace ServiceTests.Service{ public class ComponentRewriteFacility : IFacility { readonly IDictionary<Type, Type> _rewrites;
public ComponentRewriteFacility() { _rewrites = new Dictionary<Type, Type>(); }
public void AddRewrite<I, T>() where T : I { _rewrites.Add( typeof(I), typeof(T) ); }
public virtual void Init( IKernel kernel, IConfiguration facilityConfig ) { if( kernel == null ) throw new ArgumentNullException( "kernel" ); kernel.ComponentRegistered += ComponentRegistered; }
public void Terminate() { }
void ComponentRegistered( string key, IHandler handler ) { if( !ShouldRewrite( handler.ComponentModel ) ) return; handler.ComponentModel.Implementation = _rewrites[handler.ComponentModel.Service]; }
protected virtual bool ShouldRewrite( ComponentModel componentModel ) { return _rewrites.ContainsKey( componentModel.Service ); } }}
And in our test suite initializer we add the “re-write rule” like this:
IWindsorContainer container = new WindsorContainer();container.AddFacility<ComponentRewriteFacility>( f => f.AddRewrite<IUsernamePasswordVerifier, AnythingGoesUsernamePasswordVerifier>() );container.AddFacility<WcfFacility>();container.Install( Castle.Windsor.Installer.Configuration.FromXmlFile( "Windsor.xml" ) );
Like it? Not? Have a better solution? Please let me know!
Advertisement