1

I'm building a CMS and it has many extension points (Data/ContentTypes, Plugins, Macros, Themes) and some of those extensions need to register services. So far extensions only depend on 'MyProject.Core' library and it would be nice if they wouldn't be dependant on any specific IoC framework. Now I'm thinking if I should build another layer to hide IoC specific registrations. The problem is that I need some advanced functionality.

E.g. NHibernate implementation of 'Data/ContentType' services (Castle Windsor style)

container.Register(Component.For<IPageRepository>().ImplementedBy<NHPageRepository>());
container.Register(Component.For<ISessionFactory>().Instance(NHibernateHelper.CreateSessionFactory()));
container.Register(Component.For<ISession>().UsingFactoryMethod(c => c.Resolve<ISessionFactory>().OpenSession()).LifeStyle.PerWebRequest);

Third line is the "hard one". I could make an interface like

interface IMyContainer
{
    Register<TService>(Func<IMyContainer,TService> factoryMethod)
    Register<TService>(Func<IMyContainer,TService> factoryMethod, LifeStyle lifeStyle)
    // ...
}

but "translating" this registration (my IoC abstraction)

public class NHInstaller :  IInstaller
{
    public void Install(IMyContainer container)
    {
        container.Register<ISession>(c => c.Resolve<ISessionFactory>().OpenSession(), LifeStyle.PerRequest);
    }
}

to this (Windsor)

container.Register(Component.For<ISession>().UsingFactoryMethod(c => c.Resolve<ISessionFactory>().OpenSession()).LifeStyle.PerWebRequest);

could be quite hard.

So, should I try to make that abstraction? Any helpful resources? Or should I just pick a IoC container and stick with it?

I could also make source code of an existing tool (Castle Windsor or Ninject) a part of my library, but I don't really understand those licenses. Can I do that? Can I change namespaces and class names to fit the structure of my app? I'm going to release the source code and I don't really care what the license is going to be.

Mike Koder
  • 1,898
  • 1
  • 17
  • 27

2 Answers2

3

It depends on what you mean by "hide." Best practice is that only one place in your application (the Composition Root) knows about the IoC container. Stick to the Hollywood Principle - avoid having multiple classes that know about the IoC container. In other words don't pass the container around; if a non-root class needs to create other objects then inject a factory into it.

If you're writing a framework and want to allow consumers to plug in their IoC container framework of choice, you could use the Common Service Locator library. That is likely overkill for most projects. (See Mark Seemann's excellent link for the reason I changed the wording).

Community
  • 1
  • 1
TrueWill
  • 25,132
  • 10
  • 101
  • 150
  • I already have a concept of "ServiceProvider" which only returns instances of services and is not bound to any IoC container. The question is whether one should be able to _register_ services without knowing the underlying IoC container (and how). – Mike Koder Aug 28 '11 at 22:48
  • For registering services, I'd say using the IoC container is fine unless your customers are developers who may want to use their container of choice. In that case see my second paragraph above. For service providers, be careful to avoid the [Service Locator anti-pattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx). – TrueWill Aug 29 '11 at 00:49
  • 1
    +1 except for the Common Service Locator part. If you're writing a framework, a DI Container should in no way figure in the API, and neither is it necessary: http://stackoverflow.com/questions/2045904/dependency-inject-di-friendly-library/2047657#2047657 – Mark Seemann Aug 29 '11 at 07:06
  • @Mark - great comment; I revised the wording and added your link. Thank you! – TrueWill Aug 29 '11 at 15:42
1

Short answer - no, the abstraction is useless, you'd be wasting your employer's money. Use Installers to partition the registration instead.

Krzysztof Kozmic
  • 27,267
  • 12
  • 73
  • 115
  • This is a hobby project and a learning experience so there's no rush. I certainly don't need that much abstraction. I don't even need to change from NHibernate to MongoDB easily, but I have included that possibility anyway. So, if it's not needed in the "real world" modular applications to make IoC container easily changeable, I won't make it either. – Mike Koder Aug 28 '11 at 21:56
  • Regardless, abstracting container's registration in an application is a futile task. Even if you'd decide to swap NHibernate for Mongo, if done right, all your registration related change would be to delete `NHibernateInstaller` and create `MongoInstaller`. And you get to use all the power of your container. – Krzysztof Kozmic Aug 28 '11 at 22:00