Usage of IoC Containers; specifically Windsor
Asked Answered
L

5

28

I think the answer to this question is so obivous that noone has bothered writing about this, but its late and I really can't get my head around this.

I've been reading into IoC containers (Windsor in this case) and I'm missing how you talk to the container from the various parts of your code.

I get DI, I've been doing poor mans DI (empty constructors calling overloaded injection constructors with default parameter implementations) for some time and I can completely see the benefit of the container. However, Im missing one vital piece of info; how are you supposed to reference the container every time you need a service from it?

Do I create a single global insance which I pass around? Surely not!

I know I should call this:

WindsorContainer container = new WindsorContainer(new XmlInterpreter());

(for example) when I want to load my XML config, but then what do I do with container? Does creating a new container every time thereafter persist the loaded config through some internal static majicks or otherwise, or do I have to reload the config every time (i guess not, or lifecycles couldnt work).

Failing to understand this is preventing me from working out how the lifecycles work, and getting on with using some IoC awsomeness

Thanks,

Andrew

Leroi answered 14/12, 2008 at 23:52 Comment(0)
U
24

99% of the cases it's one container instance per app. Normally you initialize it in Application_Start (for a web app), like this.

After that, it's really up to the consumer of the container. For example, some frameworks, like Monorail and ASP.NET MVC allow you to intercept the creation of the instances (the controllers in this case), so you just register the controllers and their dependencies in the container and that's it, whenever you get a request the container takes care of injecting each controller with its dependencies. See for example this ASP.NET MVC controller. In these frameworks, you hardly ever need to call or even reference the container in your classes, which is the recommended usage.

Other frameworks don't let you get in the creation process easily (like Webforms) so you have to resort to hacks like this one, or pull the required dependencies (that is, explicitly calling the container). To pull dependencies, use a static gateway to the container like this one or the one described by maxnk. Note that by doing this, you're actually using the container as a Service Locator, which doesn't decouple things as well as inversion of control. (see difference here and here)

Hope this clears your doubts.

Unparalleled answered 15/12, 2008 at 3:10 Comment(6)
Actually, a lot of environments do have a "global root" class somewhere, if you look for it. Silverlight and WPF have the App class (code-behind for the App.xaml) which is as good a place as any to anchor an IOC container. For larger WPF and Silverlight, you'd definitely want to look at Prism, which provides both large-scale structuring tools and Unity, which is MS's IOC container.Rostock
@Cylon: and ASP.NET has Application_Start(), but that doesn't mean it will let you intercept object creation. It only means you have a place to setup the container.Unparalleled
ASP.NET WebForms Page creation can be intercepted and Pages by 'built up' for DI by making a PageHandlerFactory and registering the implementation in web.config. See cuttingedge.it/blogs/steven/pivot/entry.php?id=81#commKrystakrystal
@Mufasa: that's not creation interception. You're working with an already constructed instance. For example, you can't proxy it.Unparalleled
Well, maybe it's not technically intercepting, but it gets the job done, doesn't it? With only one web.config registration to a small class that implements one method. ASP.Net Web Forms is obviously not very pure when it comes to coding standards anyway. But many coders still have to live with it for now. Hopefully, this will help them keep their sanity until they get a chance to get off of Web Forms.Krystakrystal
I wish I knew what the link at "like this" was. :(Rawlins
J
3

Generally you want to keep only one instance for the lifetime of the entire application. What I do most of the time is I initialize the container when the app starts, and then I use typed factories for container-unaware pulling of objects.

Other popular approach is to wrap the container instance with static class and use that static class to access your (singleton) container. You can find an example of that in Ayende's Rhino.Commons library here. This approach however has severe drawbacks and should be avoided.

Jansen answered 22/12, 2008 at 22:15 Comment(2)
"What I do most of the time is I initialize the container when the app starts, and then I pass it around to those who need it." I like this idea. Do you think you could provide a link or sample?Yuille
Have a look at Windsor's documentationJansen
K
1

I use this example from Michael Puleio's blog on using a HttpModule to handle the build up of my dependencies using Unity. http://blogs.msdn.com/mpuleio/archive/2008/07/17/proof-of-concept-a-simple-di-solution-for-asp-net-webforms.aspx

Khamsin answered 15/12, 2008 at 14:19 Comment(0)
G
1

As the other answers here state there are a lot of choices, and again we're left to ourselves to figure out what is best in our case.

That said, IMO having a global container that is accessed throughout your application somewhat breaks isolation in that a lot of code now depends on the one global class. Also, for applications that is split out into several assemblies, the global container must be made accessible to all these assemblies.

With Unity you can actually have a IUnityContainer parameter in your constructor and the container will automatically inject itself into the instance when you resolve the class. This way, for services that needs to resolve other services you pass in the container instead of forcing the class to reference the external class.

Not sure how other frameworks support this scenario (Windsor will inject IKernel).

Gone answered 23/3, 2009 at 14:18 Comment(6)
"for applications that is split out into several assemblies, the global container must be made accessible to all these assemblies." No, one the main points of any IoC container is to be non-intrusive. Windsor and others achieve and recommend that.Unparalleled
@mausch - how does it achieve that, when there seems to be a general recommendation to have a shared singleton container? Or am I wrong in this assumption? I don't see how my answer contradicts IoC points. Its just how one uses IoC frameworks, not the frameworks themselves, that feels intrusive.Gone
Yes, there is a single container, but no one should know about it except the startup code and some specific glue code (i.e. a ASP.NET MVC ControllerFactory like mvccontrib.googlecode.com/svn/trunk/src/MvcContrib.Castle/…).Unparalleled
Otherwise it's not dependency injection and inversion of control but service location. See martinfowler.com/articles/…Unparalleled
I have to say, I'm new to IoC and I still can't work out where containers are meant to be used. I'm going to take a stab here and say one per assembly?Mimi
@Sir Psycho - the actual container should live at the application level, usually created and initialized during app bootstrap. With IoC/DI used consistently throughout that application, you only have to access the container once at bootstrap to create your root instance (a main view, presenter, whatever) and the container will take care of building whatever dependencies are needed.Gone
E
0

I'm using an implementation of this interface:

public interface IResolver
{
    object Resolve(Type type);
    object Resolve(string name);

    T Resolve<T>() where T : class;
    T Resolve<T>(string name) where T : class;
}

Which is actually wrapped in global static class, for example:

public static class Resolver // : IResolver
{
    private static IResolver _current;

    public static object Resolve(Type type)
    {
        return Current.Resolve(type);
    }

    public static object Resolve(string name)
    {
        return Current.Resolve(name);
    }

    public static T Resolve<T>() where T : class
    {
        return Current.Resolve<T>();
    }

    public static T Resolve<T>(string name) where T : class
    {
        return Current.Resolve<T>(name);
    }

    private static IResolver Current
    {
        get
        {
            if (_current == null)
            {
                _current = new SpringResolver();
            }

            return _current;
        }
    }
}

Also I'm trying to follow the simple rule - use Resolver class as less as possible, instead inject services in objects that need those services.

Exogamy answered 15/12, 2008 at 0:5 Comment(1)
However (I realize I'm late to the game here), if instead of having Resolver be a global static class, and you pass it as an injected argument to objects that need to create their own objects, then it becomes an Abstract Factory, which is a better thing than a service locator, right?Lexicon

© 2022 - 2024 — McMap. All rights reserved.