castle.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<facilities>
<facility id="testfacility">
<assemblies>
<assembly>SomeAssembly</assembly>
</assemblies>
</facility>
</facilities>
<components>
<component id="somecomponent"
service="Container.Tests.ISomeComponent, Container.Tests"
type="Container.Tests.SomeSpecializedComponent, Container.Tests"/>
</components>
</configuration>
TestFacilityFixture.cs
namespace Container.Tests
{
interface ISomeComponent { }
public class SomeComponent : ISomeComponent { }
public class SomeSpecializedComponent : SomeComponent { }
public class TestFacility : AbstractFacility
{
public static IList<string> RegisteredComponents;
public static bool ConfigurationAvailable;
protected override void Init()
{
ConfigurationAvailable = FacilityConfig != null &&
FacilityConfig.Children["assemblies"] != null;
Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
void Kernel_ComponentRegistered(string key,
Castle.MicroKernel.IHandler handler)
{
RegisteredComponents.Add(key);
}
}
[TestFixture]
public class TestFacilityFixture
{
const string ConfigFile = "castle-facility.config";
[SetUp]
public void SetUp()
{
TestFacility.ConfigurationAvailable = false;
TestFacility.RegisteredComponents = new List<string>();
}
static void VerifyDesiredState(IWindsorContainer container)
{
Assert.That(TestFacility.ConfigurationAvailable, Is.True,
"configuration settings were not available");
Assert.That(TestFacility.RegisteredComponents,
Has.Member("somecomponent"), "Facility was not notified of the
component's registration");
Assert.That(container.Resolve<ISomeComponent>(),
Is.InstanceOfType(typeof(SomeSpecializedComponent)), "Expecting
instance of SomeSpecializedComponent");
}
[Test]
//FAILS:
// most examples I've seen register facilities and components
in constructor after config is parsed
// but faicilities added after config are not notified when
components are registered
public void TestConstructorInitialization()
{
var container = new TestContainer(new XmlInterpreter(ConfigFile));
VerifyDesiredState(container);
}
[Test]
//FAILS:
// if facilities added before parsing configuration the
facility configuration settings are not available
public void TestInstallStrategy()
{
var container = new TestContainer();
container.RegisterFacilities();
container.Install(Configuration.FromXmlFile(ConfigFile));
container.RegisterComponents();
VerifyDesiredState(container);
}
[Test]
//FAILS:
// Installer is run during creation even though no config file
has been specified yet
public void TestSpecializedInstallerStrategy()
{
var container = new TestContainer(new DefaultKernel(), new
SpecializedComponentInstaller());
container.Install(Configuration.FromXmlFile(ConfigFile));
container.RegisterComponents();
VerifyDesiredState(container);
}
[Test]
//FAILS:
// Seems that the config file settings are not merged
public void TestAddFacilityToConfigurationStor()
{
var configStore = new DefaultConfigurationStore();
var facilityTypeInfo = new MutableConfiguration("facility");
facilityTypeInfo.Attribute("id", "testfacility");
facilityTypeInfo.Attribute("type",
typeof(TestFacility).AssemblyQualifiedName);
configStore.AddFacilityConfiguration("testfacility",
facilityTypeInfo);
var container = new TestContainer(configStore);
container.Install(Configuration.FromXmlFile(ConfigFile));
container.RegisterComponents();
VerifyDesiredState(container);
}
}
public class TestContainer : WindsorContainer
{
public TestContainer() { }
public TestContainer(IKernel kernel, IComponentsInstaller
installer) : base(kernel, installer) { }
public TestContainer(IConfigurationStore configurationStore) :
base(configurationStore) { }
public TestContainer(IConfigurationInterpreter interpreter) :
base(interpreter)
{
RegisterFacilities();
RegisterComponents();
}
public void RegisterFacilities()
{
if(Kernel.GetFacilities().Count(t=>t is TestFacility) ==
0) AddFacility<TestFacility>("testfacility");
}
public void RegisterComponents()
{
if(!Kernel.HasComponent("somecomponent"))
{
Register(Component.For<ISomeComponent>().ImplementedBy<SomeComponent>().Named("somecomponent"));
}
//....
}
}
class SpecializedComponentInstaller : DefaultComponentInstaller
{
protected override void
SetUpFacilities(Castle.Core.Configuration.IConfiguration[]
configurations, IWindsorContainer container)
{
base.SetUpFacilities(configurations, container);
if (container.Kernel.GetFacilities().Count(t => t is
TestFacility) == 0)
container.AddFacility<TestFacility>("testfacility");
}
}
}
If you specify the facility type rather than just id in config file
then all tests pass. (<facility id="testfacility"
type="Container.Tests.TestFacility, Container.Tests">)
So if I want to override any services in the config file it seems I
need to register the facility in the config file rather than in code.
The best alternative I can think of is not to use the component type
attribute to override existing services but instead to add an element
in the facility configuration like this I guess:
<somecomponent>Container.Tests.SomeSpecializedComponent,
Container.Tests</somecomponent>
Thoughts?
- Kurt