4

OK, maybe here is such question already, but I didn't find it..

The problem

We have big enterprise application with a lot of entry points. App contains part like:

  • Server
  • Desktop Client
  • Some console utilities
  • .NET API (separate assembly, with root class called like MyAppAPI)
  • COM API (the same, separate assembly, you can access to API from, for example VBScript, by Set api = CreateObject("MyApp.MyAppAPI")
  • Java API (again, the same)
  • Messaging API (separate assembly, used for communicating between layers through messages queues)

We use Unity as DI container in this app. Everything is cool in Server/DesktopClient/Console utilities etc. - there are very concrete entry points, so we just initialize composition root object there, initialize tree of objects/dependencies, and everything works like a charm. Them problem is with our APIs.

#1

How to deal with DI in libraries/frameworks?

From the link above:

The Composition Root is an application infrastructure component.

Only applications should have Composition Roots. Libraries and frameworks shouldn’t.

Yeah, it's cool, but.. I want to use DI in my API, it's huge! How to deal one with other?

#2

We have dependencies, which preferably should be singletons (e.g. some factories, which control lifetime of created objects). But, we can create some instances of API objects, how to share this singleton instances between them? Even more - we can create some instances of .NET API objects and one/some instances of COM API objects in the same domain (if you want, I can explain in the comment when it's possible)..

What I have now

As I said, there is no problem with apps, the problem exists in libraries (APIs). So, what I have now

  • I have class ShellBase
  • this class contains static field _Shells and public static methods Get and Release
  • there is hierarchy between containers (e.g. APIs' containers are inherited from MessagingAPI, Server and DesktopClient containers are inherited from .NET API container etc.)
  • when somebody ask for new shell (through Get method), ShellBase checks if there is already such container (or super-container, from subclass), and returns that instance. Or creates new one

I don't like this way, but this is the best what I can imagine right now.

Possible solution

Create something like APIFactory, which will create our API objects, but it looks.. too complicated for end-users. I don't want to write in user documentation: "Please, create and keep APIFactory instance first, then you can create API instances using this factory". It's ugly. Our users should write just var api = new API(), and use it.

So, guys, what do you think?

Elnur Abdurrakhimov
  • 44,533
  • 10
  • 148
  • 133
chopikadze
  • 4,219
  • 26
  • 30

1 Answers1

0

1: I have seen other frameworks/libraries where they introduce their own DI container abstraction, via an interface. They then use this interface internally wherever they need to reference the DI container. Adapters are used to connect their library with a specific DI container. For example, Davy Brion's Agatha project has the following Container interface: https://github.com/davybrion/Agatha/blob/master/Agatha.Common/InversionOfControl/IContainer.cs and he supplies adapters for the most used DI containers.

2: Im not entirely sure I understand your problem here, but most, if not all, DI containers support singleton lifetime scopes, meaning your container will only ever create a single instance. For example, in ninject you would do:

kernel.Bind<IFoo>()
   .To<Foo>()
   .InSingletonScope();

Alternatively, if you want to avoid public constructors, you can make a static singleton instance of the class like you would do without a DI container. You can the register your singleton instance with the container with a factory method that returns that instance. Again, a ninject example:

kernel.Bind<IFoo>()
    .ToMethod(c => Foo.Instance);

Given the interface introduced above, you should be able to share a single container instance between your APIs (assuming you use more than one API in a given application), thereby enforcing the singleton requirement.

If this is not your problem, then maybe you can elaborate on the second problem.

Morten Jacobsen
  • 986
  • 1
  • 11
  • 31
  • Thanks a lot for your answer! Sure, I know how to define singleton instance in DI container. The problem is: how to share DI container between different instances of API objects? More I think about it, more I understand that maybe the only robust way will be to create `API factory`, but maybe somebody knows better way to do it? – chopikadze Aug 14 '12 at 07:13
  • Well if you introduce an interface for the container as indicated in 1 you can share the same container instance between API objects by either injecting the container into the API or resolve the API objects directly from the container. I'm not sure exactly what you mean by API objects though.. – Morten Jacobsen Aug 14 '12 at 07:18
  • 2
    Also see [Common Service Locator](http://commonservicelocator.codeplex.com) for a DI abstraction layer. – Randy Levy Aug 14 '12 at 14:18