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 well as the option suggested by Mauricio, it is also possible to create a Facility to achieve the expected behaviour as explained on this example page about Facilities.
Here is my implementation which is slightly more concise:
Then just decorate any properties with
[NonOptional]
and you will receive an error if there is an issue with construction.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.
As of Castle Windsor 3.2 there's new a cool addition that is Diagnostic logging in the container.
So if you do this for example in an ASP.NET MVC app:
you can redirect the logs caught by Windsor to your configured log4net logger.
The type of information currently being logged includes: