Pregunta

I'm working on a project at the moment and it's going to be primarily library-based.

I want the library to be consumed using dependency injection, but I want the library to be largely agnostic towards the container being used.

I wrote a "bridge" library a while back to make this sort of thing easier, but I wasn't sure if this was actually the right approach? (library: https://github.com/clintkpearson/IoCBridge)

I don't want to reference the DI-technology (Ninject, Windsor etc) directly from my library as then it makes it inflexible for people using it.

There are a few other questions on SO in a similar vein but none of them seem to actually address the problem satisfactorily.

As a side note: I realise I could just make sure the library adheres to the general idiom and uses interfaces & ctor arguments for dependencies, and then just leave it up to the consuming app to register the types in the containers.

The only issue I can see with this (and correct me if I'm wrong) is that this requires the consuming app to actually know which types link to which interfaces, whether some need to be registered as singletons etc... and from a plug-and-play usage perspective that's pretty poor.

¿Fue útil?

Solución

A good DI implementation should enable DI on any object, regardless of the latter being DI-agnostic or not.

Prism is a bad example, as the last time I used it (2 years ago) it required objects to be DI-agnostic by enforcing use of the [Injection] attribute. A good non-DI-agnostic example is Spring Framework (extremely popular DI framework for Java, has a .NET port called Spring.NET), which allows enabling DI via so-called context files - these are xml files that describe dependencies. The latter need not be part of your library, leaving it as a completely independent dll file.

The example of Spring can tell you that you should not have any specific configuration, prerequisites or patterns to follow in order to make an object injectable, or allow objects to be injected to it, besides the programming to interfaces paradigm, and allowing programmatic access to suitable constructors and property setters.

This does not mean that any DI framework should support manipulation of plain CLR (.NET) objects, a.k.a. POCO-s. Some frameworks rely only on their specific mechanisms and may not be suitable to use with DI-independent code. Usually, they would require direct dependency on the DI framework to the library, which I think you want to (and probably should) avoid.

Otros consejos

It's a bit controversial but I suggest using Poor Man's Injection. I'm not saying it's great but it has some valid use cases(just like Service Locator) under some constraints. It will require a little more maintenance but it will save you from depending another libray for IoC container registration. You should read Mark Seemann's article on the subject.

I recently implemented this approach in a very simple library of mine. Basically you write two constructors for the public classes of the library.

internal SitemapProvider(IActionResultFactory actionResultFactory, IBaseUrlProvider baseUrlProvider)
{
    _actionResultFactory = actionResultFactory;
    _baseUrlProvider = baseUrlProvider;
}

public SitemapProvider() : this(new ActionResultFactory(), new BaseUrlProvider()) { }

As you can see only the second constructor is public and you fill the dependencies yourself. This also provides encapsulation at assembly level. You can still test this class by adding a InternalsVisibleTo attribute to the assembly and use dependency injection in your library freely. The user can also create instances with new keyword or add this class's interface to their IoC registration.

I don't know if there's a widely adopted IoC container registration library in .NET. I thought about writing one myself but each container has their unique features and it gets more complicated with object life cycles. Also people will be uneasy about depending on another library for this.

I think you have slightly misinterpeted the scope of Dependency Injection. DI is a pattern, a subset of IoC, and IoC containers make DI easy and convenient - they assist with dependency resolution. IoC can be categorised as a superset of several methodologies, of which DI is one part.

You do not need IoC frameworks in order to make Dependency Injection work.

If you really insist on using an IoC container instead of leveraging regular DI (i.e. constructor parameters or mandatory property setting) then you should nominate the container/framework, don't try to be all things to all people by trying to kludge together adapters or bridges. Be cautious about over-engineering. A library by its very definition means it has a limited and well defined set of functionality, therefore it should not need a large amount of dependencies injected.

They'll most likely want to implement their own versions of some of the interfaces

You don't need an IoC framework to achieve this. If your constructors have their parameters defined as interfaces then in effect you've already achieved DI - the dependency is injected at construction time and you know nothing about the actual concrete implementation of it. Let the calling code worry about the nitty gritty details of which implementation of that interface it wants to pass in.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top