2

I have a library handling interactions with a database backend that I use in most of my applications and now want to convert to an IoC structure (using Autofac internally, but its usage should not depend on a specific IoC container or even on using one at all). How would I go about wiring up the library's internal dependencies in a "default" way without the application having to take care of it, but with the ability to provide other implementations if necessary ?

As an example: The library can store and read connection credentials for different backend servers on/from the user's hard drive. Part of this information, at least the passwords, is encrypted, usually with the default encryption defined in the library - so normally I won't want to care about the details in my application that uses the library. But there might be cases where I need to provide a different encryption algorithm (e.g. through an IConnectionEncryption interface) when calling the logon method from my application.

What do I need to do in my library and in my application to achieve this ?

TeaDrivenDev
  • 6,591
  • 33
  • 50
  • Do you need to apply different implementations as an option at startup, or on the fly at runtime due to a shift in context? – Marc L. Oct 04 '11 at 03:15
  • 1
    Possible duplicate: http://stackoverflow.com/questions/2045904/dependency-inject-di-friendly-library – Mark Seemann Oct 04 '11 at 06:06
  • @MarcL. Only at startup; if an application provides its own implementation I'd want that to be used throughout. – TeaDrivenDev Oct 04 '11 at 09:54
  • @MarkSeemann I found that question later on, and I guess your answer there pretty much says it all as far as the library's API is concerned. However, I was hoping to be able to handle the library's internal dependencies and default implementations through an IoC container as well, though that seems difficult as it would not have one single point from which all code is eventually called that could serve as my composition root (for the library only; I want it to be container agnostic on the outside). – TeaDrivenDev Oct 04 '11 at 10:02

3 Answers3

3

In general you want the application to take care of it. You said it yourself - you want to do the DI container configuration in the application composition root (which is best practice).

If you keep any knowledge of the DI container out of the library, other developers will be able to use their container of choice (or no container at all).

Going the other way, you may end up with something like Rhino Service Bus that (mostly) depends on a particular DI container. If your project is open source, you're likely to get requests for compatibility with container X, version Y. Even if it's closed-source, your team may want to change containers someday.

Hopefully @Mark Seemann can give a canonical answer. :)

TrueWill
  • 25,132
  • 10
  • 101
  • 150
  • 1
    +1 This a good explanation of the reasons why you don't want to encapsulate a particular container. For options for doing that, see the link I added to the question. – Mark Seemann Oct 04 '11 at 06:07
0

The Common Service Locator might be able to help you. Its job is to provide a common interface for multiple IoC containers to utilize, so you or other consumers of your library can pick which container to integrate.

neontapir
  • 4,698
  • 3
  • 37
  • 52
0

I am assuming, based on your question title, that your goal is to configure your library from the composition root, but not require the consuming application to know how to register everything for it.

The easiest way to do this with Autofac is to create one or more modules:

public class SecurityModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register<Sha256ConnectionEncryption>.As<IConnectionEncryption>();

        // ...other security-related registrations...
    }
}

Now, the application can simply register the module:

// In composition root

builder.RegisterModule<SecurityModule>();

To register a different implementation of an interface, you can simply provide that registration after registering the module. Autofac takes a last-in-wins approach to registrations, meaning you can change any of the default decisions made by the module:

// In composition root

builder.RegisterModule<SecurityModule>();

builder.Register<Sha512ConnectionEncryption>().As<IConnectionEncryption>();

This will result in Sha512ConnectionEncryption being injected wherever IConnectionEncryption is needed in the application.

Bryan Watts
  • 44,911
  • 16
  • 83
  • 88