Dependency Injection and Library / Framework

OK, maybe this is the question already, but I did not find it ..

Problem

We have a large enterprise application with many entry points. The application contains a part like:

  • Server
  • Desktop client
  • Some console utilities
  • .NET API (standalone assembly with a root class called MyAppAPI )
  • COM API (same, separate assembly, you can access the API from, for example, VBScript, Set api = CreateObject("MyApp.MyAppAPI")
  • Java API (again)
  • Message API (a separate assembly used to communicate between layers through message queues)

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

# 1

How to work with DI in libraries / frames?

From the above link:

Composition root is a component of the application infrastructure.

Only applications should have composition roots. Libraries and frameworks should not.

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

# 2

We have dependencies that should preferably be single point (for example, some factories that control the lifetime of created objects). But we can create multiple instances of API objects, how to share these singleton instances between them? Moreover, we can create several instances of .NET API objects and one or several instances of COM API objects in the same domain (if you want, I can explain in the commentary when this is possible).

What i have now

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

  • I have a ShellBase class
  • this class contains the _Shells static field and the public static methods Get and Release
  • there is a hierarchy between containers (for example, API containers are inherited from MessagingAPI, Server and DesktopClient containers, inherited from a .NET API container, etc.).
  • when someone requests a new shell (via the Get method), ShellBase checks to see if there is such a container (or a super container from a subclass) and returns this instance. Or creates a new

I don’t like it, but it’s the best I can imagine right now.

Possible Solution

Create something like APIFactory that will create our API objects, but looks too complicated for end users. I don’t want to write in user documentation: "Please create and save an APIFactory instance first, then you can create API instances using this factory." This is ugly. Our users should only write var api = new API() and use it.

So guys, what do you think?

+4
source share
1 answer

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

2: I'm not quite sure that I understand your problem here, but most, if not all, DI containers support single-user Singleton scopes, that is, your container will only create one instance. For example, in ninject you would do:

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

Alternatively, if you want to avoid creating generic constructors, you can make a static instance of a singleton class, as if you were doing this without a DI container. You can register your singleton instance with a container using the factory method that returns this instance. Again, an example of ninject:

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

Given the interface introduced above, you should be able to exchange an instance of one container between your APIs (provided that you use more than one API in this application), thereby observing the singleton requirement.

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

0
source

All Articles