cubetwo1729
cubetwo1729

Reputation: 1516

How to pass resolved instances from Inversion of Control to classes in application?

I am using Castle Windsor's inversion of control in my application. When the application first loads, IWindsorContainer.Resolve resolves the components (in particular, factories) into instances.

For example, ILoggerFactory gets resolved into MyCustomLoggerFactory (or anything which implements ILoggerFactory), whose method CreateLogger() creates a logger. I want to have each class call ILoggerFactory.CreateLogger(). However, I do not want to pass an ILoggerFactory into the constructor of each class.

How can each class access the particular ILoggerFactory factory to use without having to call IWindsorContainer.Resolve every single time?

Upvotes: 5

Views: 536

Answers (2)

Ufuk Hacıoğulları
Ufuk Hacıoğulları

Reputation: 38468

If you do not want to polute your API, you can use Ambient Context pattern here like this:

public abstract class Logger
{
    static Logger()
    {
        Current = new DefaultLogger();
    }

    public static Logger Current { get; set; }

    // your Logger members
    public abstract void Log();
}

public class DefaultLogger : Logger
{
    public override void Log()
    {
        //do something
    }
}

Upvotes: 2

kmp
kmp

Reputation: 10865

As far as I know there are three ways to get hold of a dependency out of the windsor container (incidentally you shouldn't ever need to explicitly resolve anything, except possibly some bottom level class, just make sure it is all registered with the container and the dependencies are wired up for you):

  1. Add a constructor argument (this is considered a required dependency)
  2. Add a property to the class (this is considered an optional dependency)
  3. Get hold of the IWindsorContainer instance and call Resolve (this is usually a bad idea)

Normally for logging specifically you would make that an optional dependency so go for option 2 and do something like this (I used your ILoggerFactory idea, I actually wouldn't define my own factory for this - see later):

private ILoggerFactory _loggerFactory = LoggerFactory.NullLoggerFactory;

public ILoggerFactory LoggerFactory
{
    get { return _loggerFactory; }
    set { _loggerFactory = value; }
}

That way, in your code, you can use the LoggerFactory property and if one has not been added to the container you get the "null" version (this is just an instance of ILoggerFactory that creates a logger that does nothing) and if it has you get the real version (you could just check for null when you use it, or if you know that there will be one just use it). You define this property on the classes where you need the logger and you are done.

An Aside

Incidentally, there is such a thing as the logging facility in Windsor that you could use instead - I have a small issue with that since I don't really want a windsor interface throughout my code base so what I have done in the past is defined my own ILogger interface (and a null implementation of it) and then created a "castle logger proxy" that implements my ILogger interface but has a dependency on the castle ILogger which is what it calls into to do the actual logging. That way I can separate that out into it's own assembly and my application can have no idea that Windsor is injecting the dependencies.

Maybe you don't care though, just thought I would mention it.

Upvotes: 3

Related Questions