Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have Castle Windsor resolve property dependancies when you dont have a reference to the container?

We have a solution whith multiple projects representing the layers of our application. e.g.

Domain

Data

Logic

WebUI

Our Castle Windsor container is referenced from our web layer and we then cascade these dependancies up through our layers. For example...

// In Domain
public interface IFooRepository
{
    void DoSomething();
} 

// In Data
public class FooRepository : IFooRepository
{
    public void DoSomething()
    {
        // Something is done
    }
}

// In Logic
public class MyThingManager
{
    private readonly IFooRepository fooRepository;

    public MyThingManager(IFooRepository fooRepository)
    {
        this.fooRepository = fooRepository;
    }

    public void AMethod()
    {
        this.fooRepository.DoSomething();
    }

}

// In Web
// in some controller....
var newManager = new MyThingManager(WindsorContainer.Resolve<IFooRepository>());
newManager.DoSomething();

and this works nicely until our managers have lots of members that have their own dependancies. When this happens we end up resolveing both the managers dependancies and their dependancies depandancies and cascading them up from the web layer. This results is some rather large constructors.

Is there a more elegant way of, for example having the inner components of a manager resolve it's own dependancies without having access to the container?

Bear in mind that ONLY the web layer has access to the container (to prevent a circular project dependancy), so only the web layer can activly WindsorContainer.Resolve() the logic layer can't so the only way to cascade a dependancy without the containers assistance was to resolve it in the web layer then pass it up the chain using it's interface.

like image 539
Rich Andrews Avatar asked Apr 11 '12 11:04

Rich Andrews


1 Answers

Short answer is that whenever you see .Resolve<T> you are probably doing it wrong. As @Steven mentioned, you want to use the inbuilt features of Windsor to provide you with constructor injection (and/or property injection). This means that WindsorContainer needs to know the object that is at the root of your object graph.

In your case, you would walk up the tree of objects (from MyThingyManager) until you get to the root object. For example, in an ASP.NET MVC app this would be the controller that contains the action being called. For the MVC3 case, you would use a DependencyResolver to kick off the injection of all dependencies.

Further, what I have found useful with Windsor in the past is to have a different Installer per component (assembly). And then register these installers at the base of the process that is hosting the application.

So in each component you would have an installer like:

public class Installer : IWindsorInstaller
{
        public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
        {
            container.Register(
                Component.For<IMyThingManager>().ImplementedBy<MyThingManager>(),
                Component.For<IFooRepository>().ImplementedBy<FooRepository>()
                );
        }
}

And then in the Global.asax.cs Application_Start you would have something like:

var container = new WindsorContainer();
container.Install(FromAssembly.This());
container.Install(FromAssembly.Containing(typeof(ComponentThatContains.MyThingManager.Installer)));

This gives you a way to manage all dependencies down the entire object graph and resolve through constructor injection. Hope this helps.

like image 130
Davin Tryon Avatar answered Nov 14 '22 08:11

Davin Tryon