2

I'm using the Nhibernate persistence facility from Windor's tutorial:

Kernel.Register(
    Component.For<ISessionFactory>()
        .UsingFactoryMethod(config.BuildSessionFactory)
        .LifeStyle.Singleton,
    Component.For<ISession>()
        .UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
        .LifeStyle.PerWebRequest);

Sometimes my call to config.BuildSessionFactory will fail (maybe my mappings are wrong, or my connection string is invalid or whatever). In the debugger, I can see the Nhibernate exception being thrown. Now Windsor can no longer resolve my ISession either because the factory itself couldn't be instantiated.

The problem is that it doesn't seem to complain about it. Without the debugger, the exception is silently thrown away and the only symptom I have in my app is that all my ISession dependencies are suddenly null. What's the right way to deal with exceptions in UsingFactoryMethod? Is there some way I can tell Windsor to bubble up this exception to my app?

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
Ragesh
  • 2,800
  • 2
  • 25
  • 36
  • I'm looking for this too... in the meantime I was able to catch the exception in a log file to better understand what's going on with Windsor: http://stackoverflow.com/a/21007268/114029 – Leniel Maccaferri Jan 08 '14 at 22:02

1 Answers1

1

The only why I can see Castle eating the exception is if the session is being injected as a property, which makes Castle consider it optional.

Here's how I fixed it... I created an activator that throws an exception when it fails to set a property's value:

public class StrictComponentActivator : DefaultComponentActivator
{
    public StrictComponentActivator(ComponentModel model, IKernelInternal kernel,
        ComponentInstanceDelegate onCreation,
        ComponentInstanceDelegate onDestruction)
        : base(model, kernel, onCreation, onDestruction) { }

    protected override void SetUpProperties(object instance, CreationContext context)
    {
        instance = ProxyUtil.GetUnproxiedInstance(instance);
        var resolver = Kernel.Resolver;
        foreach(var property in Model.Properties)
        {
            var value = ObtainPropertyValue(context, property, resolver);

            if(value != null)
            {
                var setMethod = property.Property.GetSetMethod();
                try
                {
                    setMethod.Invoke(instance, new[] { value });
                }
                catch(Exception ex)
                {
                    throw new ComponentActivatorException(
                        string.Format(
                            "Error setting property {1}.{0} " +
                            "in component {2}. " +
                            "See inner exception for more information. " +
                            "If you don't want Windsor to set this property " +
                            "you can do it by either decorating it with " +
                            "DoNotWireAttribute or via registration API.",
                            property.Property.Name,
                            instance.GetType().Name,
                            Model.Name),
                        ex, Model);
                }
            }
        }
    }

    private object ObtainPropertyValue(CreationContext context, PropertySet property, IDependencyResolver resolver)
    {
        if(property.Dependency.IsOptional == false ||
            resolver.CanResolve(context, context.Handler, Model, property.Dependency))
        {
            try
            {
                return resolver.Resolve(context, context.Handler, Model, property.Dependency);
            }
            catch(Exception e)
            {
                if(property.Dependency.IsOptional == false)
                {
                    throw;
                }
                Kernel.Logger.Warn(
                    string.Format("Exception when resolving optional dependency {0} on component {1}.",
                        property.Dependency, Model.Name), e);
            }
        }
        return null;
    }
}

And then I configured most of my components with .Activator<StrictComponentActivator>()

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • 1
    Yup, it was a property being injected. I've never looked in to custom activators before, but it looks like this is the right way to fix it. Thanks! – Ragesh Aug 17 '12 at 17:55
  • What is that `ObtainPropertyValue` method? – Leniel Maccaferri Aug 22 '14 at 21:32
  • OK... I found it here https://github.com/castleproject/Windsor/blob/016730de012f15985410fb33e2eb907690fe5a28/src/Castle.Windsor/MicroKernel/ComponentActivator/DefaultComponentActivator.cs#L342. Updated your answer... – Leniel Maccaferri Aug 22 '14 at 21:56