Castle Windsor: is there a way of validating registration without a resolve call?
Asked Answered
P

1

19

My current understanding of Castle Windsor registration is that one can only validate registration by calling Resolve on a root component. But since windsor's component model knows each component's dependencies, it should be possible to test that all dependencies can be satisfied without actually instantiating anything. The main reason for wanting to do this is to have a unit test for registration that doesn't require me to stub components that call external resources on start-up.

For example. I have a class Root that has a dependency on IChild:

public class Root : IRoot
{
    private IChild child;

    public Root(IChild child)
    {
        this.child = child;
    }
}

If I register Root as IRoot, but don't register an IChild. When I call resolve like this:

var container = new WindsorContainer().Register(
    Component.For<IRoot>().ImplementedBy<Root>()
    );

container.Resolve<IRoot>();

I get an error:

MyNamespace.Root is waiting for the following dependencies: 

Services: 
- MyNamespace.IChild which was not registered. 

Is there something like:

container.TestResolve<IRoot>();

That would walk the dependency graph and check that all dependencies can be satisfied, but which doesn't actually instantiate anything?

Pneumothorax answered 23/1, 2012 at 10:9 Comment(0)
P
33

OK, It is possible. Thanks to Krzysztof Koźmic for showing me how. Not immediately obvious, but you can use Windsor's diagnostic subsystem to raise potential problems with registration. I've put together a little static method that throws if there are any misconfigured components:

private static void CheckForPotentiallyMisconfiguredComponents(IWindsorContainer container)
{
    var host = (IDiagnosticsHost)container.Kernel.GetSubSystem(SubSystemConstants.DiagnosticsKey);
    var diagnostics = host.GetDiagnostic<IPotentiallyMisconfiguredComponentsDiagnostic>();

    var handlers = diagnostics.Inspect();

    if (handlers.Any())
    {
        var message = new StringBuilder();
        var inspector = new DependencyInspector(message);

        foreach (IExposeDependencyInfo handler in handlers)
        {
            handler.ObtainDependencyDetails(inspector);
        }

        throw new MisconfiguredComponentException(message.ToString());
    }
}

You can use it like this:

var container = new WindsorContainer().Register(
    Component.For<IRoot>().ImplementedBy<Root>()
    );

CheckForPotentiallyMisconfiguredComponents(container);

In this case I get a MisconfiguredComponentException with this message:

'WindsorSpikes.Root' is waiting for the following dependencies:
- Service 'WindsorSpikes.IChild' which was not registered.

WindsorSpikes.MisconfiguredComponentException:
'WindsorSpikes.Root' is waiting for the following dependencies:
- Service 'WindsorSpikes.IChild' which was not registered.

See the castle documentation for more details on the diagnostic subsystem:

http://stw.castleproject.org/Default.aspx?Page=Debugger-views&NS=Windsor

Pneumothorax answered 23/1, 2012 at 11:16 Comment(3)
this code no longer compiles: The type 'Castle.Windsor.Diagnostics.IPotentiallyMisconfiguredComponentsDiagnostic' cannot be used as type parameter 'TDiagnostic' in the generic type or method 'Castle.Windsor.Diagnostics.IDiagnosticsHost.GetDiagnostic<TDiagnostic>()'. There is no implicit reference conversion from 'Castle.Windsor.Diagnostics.IPotentiallyMisconfiguredComponentsDiagnostic' to 'Castle.Windsor.Diagnostics.IDiagnostic<object>'. Do you know how to fix it?Trilogy
Peri, the code compiles for me, Castle 3.2 under .net 4Himation
This doesn't take typed factories into consideration. Trying to figure this out.Janelljanella

© 2022 - 2024 — McMap. All rights reserved.