Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 905
cubetwo1729 Avatar asked Apr 17 '12 17:04

cubetwo1729


1 Answers

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.

like image 70
kmp Avatar answered Oct 11 '22 17:10

kmp