I am using Castle Windsor 2.5.1 in an ASP.NET MVC project and using property injection to create an object which I expect to always be available on a base controller class. I am using a factory to create this object, however if there is an error in the constructor, I do not get a warning from Windsor at all and it just returns my object but without injecting the property.
Is this the expected behaviour, and if so, how can I get an error raised when a factory fails to return anything?
Here is an example
public class MyDependency : IMyDependency
{
public MyDependency(bool error)
{
if (error) throw new Exception("I error on creation");
}
}
public interface IMyDependency
{
}
public class MyConsumer
{
public IMyDependency MyDependency { get; set; }
}
[TestFixture]
public class ProgramTest
{
[Test]
public void CreateWithoutError() //Works as expected
{
var container = new WindsorContainer().Register(
Component.For<IMyDependency>().UsingFactoryMethod(() => new MyDependency(false)).LifeStyle.Transient,
Component.For<MyConsumer>().LifeStyle.Transient
);
var consumer = container.Resolve<MyConsumer>();
Assert.IsNotNull(consumer);
Assert.IsNotNull(consumer.MyDependency);
}
[Test]
public void CreateWithError_WhatShouldHappen() //I would expect an error since it can't create MyDependency
{
var container = new WindsorContainer().Register(
Component.For<IMyDependency>().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient,
Component.For<MyConsumer>().LifeStyle.Transient
);
Assert.Throws<Exception>(() => container.Resolve<MyConsumer>());
}
[Test]
public void CreateWithError_WhatActuallyHappens() //Gives me back a consumer, but ignores MyDependency
{
var container = new WindsorContainer().Register(
Component.For<IMyDependency>().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient,
Component.For<MyConsumer>().LifeStyle.Transient
);
var consumer = container.Resolve<MyConsumer>();
Assert.IsNotNull(consumer);
Assert.IsNull(consumer.MyDependency); //Basically fails silently!
}
}
An interesting observation, if I use this in my MVC application, I get an internal error from Windsor when calling ReleaseComponent
-- so even though it did not give me back a class with my dependency injected, it still appears to try releasing it.
As far as I know, yes, that's the intended behavior. This isn't specific to factory methods, it works like that for all optional service dependencies. Optional dependencies that throw when resolving are treated as non-resolvable. This is defined in DefaultComponentActivator.ObtainPropertyValue()
Of course, you could always override the default activator with your own if you want to change this behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With