Resolving classes without registering them using Castle Windsor
Asked Answered
D

3

17

Take the following useless program:

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer unityContainer = new UnityContainer();
        IWindsorContainer windsorContainer = new WindsorContainer();

        Program unityProgram = unityContainer.Resolve<Program>();
        Program castleProgram = windsorContainer.Resolve<Program>();
    }
}

The UnityContainer will return me an instance of Program, where as the Windsor container will throw a ComponentNotFoundException.

I can see arguments for both behaviours and don't mind which I end up with, however Prism V2 Drop 8 (the latest at time of writing) relies on the Unity behaviour internally, requesting classes that haven't been registered.

Rather than find and register all these classes for Prism I'd much rather just make Windsor behave like Unity. I haven't found anything on google to help me do this (although my terminology may be wrong) and the Windsor documentation is quite bad...

Can anyone suggest a solution to this problem?

Dagmardagna answered 15/1, 2009 at 15:34 Comment(3)
Doesn't this sort of defeat the purpose of an IoC? If you would have resolved IProgram, would it find a class-definition that implements IProgram in that case?Germicide
I guess you still get the advantage of dependency injection on the class even if you don't use an interface.Dagmardagna
jishi: the answers to your questions are no and no. No, it does not defeat the purpose of IoC. No, it does not map interfaces without them being registered.Betimes
P
9

Windsor currently does not support that, and it's by design. The reasoning is that you should explicitly register types you need so that you dont get misconfigured object.

There is however a possibility that there will be added a hook to create non-registered type at some point in the near future, as this is needed by the WCF integration facility. (Edit - it was added in v2.1 - take a look at ILazyComponentLoaders)

Anyway, regardless of lazy component loaders, the best you can do is to use fluent API to batch register all types from an assembly matching your needed criteria upfront. It's not much more code and you'll sleep better at nights.

Use lazy loaders only if you have really not enough information at startup (in your composition root) to determine what components you'll need.

Possession answered 31/1, 2009 at 22:10 Comment(2)
Why would the Windsor WCF Integration Facility have to create non-registered types?Marleah
@Marleah - so that you can say get types that are specified in your web.config only, and not duplicate the registration to the container. DRY.Possession
A
6

Windsor doesn't support that out of the box, but you can create extension methods to do this:

static class WindsorExtensions
{
    public static object ResolveType(this IWindsorContainer container, Type type)
    {
        if ( type.IsClass && !container.Kernel.HasComponent(type) )
            container.Kernel.AddComponent(type.FullName, type, LifestyleType.Transient);
        return container.Resolve(type);
     }

     public static T ResolveType<T>(this IWindsorContainer container)
     { return (T)ResolveType(container, typeof(T)); }
}

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer unityContainer = new UnityContainer();
        IWindsorContainer windsorContainer = new WindsorContainer();

        Program unityProgram = unityContainer.Resolve<Program>();
        Program castleProgram = windsorContainer.ResolveType<Program>();
    }
}
Acoustician answered 24/2, 2009 at 15:49 Comment(2)
This does not completely duplicate the functionality if Unity - only the top-level class will be automatically registered. What if class A depends on concrete class B, neither A or B are registered, and you try to resolve A? Unity will handle this, but your code above will not.Betimes
That is true. However, in all the cases where I needed to resolve an unregistered type, I never needed the "recursive" resolution of other unregistered dependencies that you describe. It should be possible to implement this on top of Windsor, as well, but personally, I had no need for it.Acoustician
F
2

Krzysztof don't be afraid to link to your own blog here :) http://devlicious.com/blogs/krzysztof_kozmic/archive/2009/11/16/castle-windsor-lazy-loading.aspx

Also, I found this simple implementation useful in my WPF app, remove the string contraint and you are close to the general case

public class ViewModelLoader : Castle.MicroKernel.Resolvers.ILazyComponentLoader {
    public IRegistration Load(string key, Type service)
    {
        if (service == null)
            return null;
        if (service.Name.EndsWith("ViewModel", StringComparison.CurrentCultureIgnoreCase))
            return Component.For(service).Named(key);
        else
            return null;
    }
}
Forster answered 11/10, 2010 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.