A few colleagues asked me to do a quick write up about the proper use of a IoC container. Particularly concerning what types you DO and DON’T register into the container. So here we go:

Things that you do and don’t wire up into an IoC container.

The big ones, the seams of the application

Components that are inherently cross-cutting concerns, and need to be “available everywhere” for possible injection. Things like:

Logging, tracing and instrumentation

Authentication and authorization

Configuration

Major application services (this includes things like the Controllers in a MVC web app)

Components that will be modularised as plug-ins / add-ins, things that get loaded dynamically. Consider using MEF as the discovery mechanism of these components.

Services with multiple implementations that can be “dynamically selected” through some means (app.config, differing registrations per DEBUG and RELEASE modes at compile-time, per-tenant configuration, etc.)

The little ones, the stylistic ones and where you “lean” on the power of your container to provide infrastructure services or as a development aid

Components that require lifetime scoping or management (transactions, sessions, units of work) and other IDisposable-like things that are longer lived than just a one-off use.

Components that are single instance. Never write “static” components.

Components that require testing / mocking out, etc. Note: I consider this to be a “development aid” and not at all mandatory.

When you want an “automatic factory” (Autofac isn’t called that for no reason!). A simple inline Func<ISomeService> expression is cleaner than a going down the stereotypical Java “Enterprise” route of manually rolling out a SomeServiceFactory class each time. Though that’s more as a result of the sad fact that they still don’t have lambdas.

And now the things that you leave out of the container

Anything that is never, and never has any need to be, referenced outside out of the module it is within.

Implementation details of a module. Your container registrations should be the facade that hides the complexities of how that module works.

Things that are essentially just DTOs, entities, POCOs, other dumb types, etc.

Little utility, helper functions.

Note: I refer to “module” a few times. This is in no way in direct reference to an assembly or package. It’s more in reference to a namespace, because components typically reside within a relatively self contained namespace with a container registration module.

Cardinal rules

Never ever call a “static” Kernel.Get / Resolve, or whatever equivalent your container might expose, anywhere. This is not dependency injection. It is service location. Which is a whole different pattern entirely. Autofac is quite neat in that it’s one of very few containers that actually does not, out of the box, provide any sort of “static” resolution/service location function. And that is good.

Only call Get / Resolve methods in your bootstrap code at the root of your object graph. And even then, there should only be less than a handful of such calls. If you can get it down to just one, then you’ve done well and you probably have an object graph that is very well expressed.

Always keep the object graph in the back of your mind. It’s a shame, in my opinion, that containers tend to keep this information hidden away in their internals. The only time you get a glimpse of it is in the exception message for when you’ve inadvertently introduced a circular dependency. Things could be so much better than this.

If you have a component that’s requiring injection of more than about five dependencies, then it should start coming onto your “radar of suspiciousness”. If it reaches about eight to nine dependencies you should almost certainly consider refactoring it and, probably, the wider namespace or module as a whole. I often see this happen on Controllers in MVC applications; the so called “fat controller” problem. Thankfully, because the dependencies are already “well expressed” (it’s just that there is too many of them) then normally refactoring such problem areas of the codebase is a relatively straight forward task.

Nowhere except your bootstrapper and container modules should reference the container, i.e. its namespaces. Arguably, your bootstrapper and container modules can be in a totally separate assembly by themselves and only that assembly holds references to your container’s assemblies. If you’re seeing namespace imports for your container all over your projects then something is very badly wrong.

Avoid the use of “service locator injections”, such as IComponentContext in Autofac. This is one of the very few ways that Autofac supports to allow you to shoot yourself in the foot. It’s not quite as bad as a “static” Kernel.Get style service locator, but it’s still pretty damn bad. As it implies you don’t actually know what possible dependencies your component has, which should be impossible. To avoid this, express your dependencies better. If there are multiple instances you wish to dynamically “select” from at runtime then you can roll your own resolution delegate function and lean on your container to implement it. Autofac makes this very easy using its IIndexrelationship. For example:

public delegate IMyService MyServiceResolver(string name);
// ... this stuff below goes in your container module ...
Func<IComponentContext, MyServiceResolver> tmp = c => {
var indexedServices = c.Resolve<IIndex<string, IMyService>>();
return name => indexedServices [name];
};
builder.Register(tmp)
.As<MyServiceResolver>()
builder.Register(c => new MyService())
.As<IMyService>()
.Keyed<IMyService>(serviceDescription.Name);
// The "keyed on" value is a string in this example.
// But, usefully, it can be any object including value types such as an enum.
// ... any time I want to resolve a IMyService, I can just do this in a constructor:
class SomeOtherComponent {
private readonly IMyService myService;
public SomeOtherComponent(MyServiceResolver myServiceResolver) {
if (myServiceResolver == null)
throw new ArgumentNullException("myServiceResolver");
this.myService = myServiceResolver("Fred");
// Technically this is a form of service location.
// However, because we have constrained the number of services that
// can be resolved to a particular *type*; then this does not
// introduce any bad practices to the codebase.
//
// Most importantly, we are not relying on any "static" magic.
// (Which is the absolute hallmark of truly bad service location.)
// Nor are we holding any references to the container.
}
}

Example of a Bootstrapper, Container Module and general structure of your Program Root

This is a little snippet of a relatively well structured IoC server application. I added some relevant comments to it.

public class Program {
private static IContainer Container { get; set; }
private static ILog Log { get; set; }
private static ProgramOptions Options { get; set; }
private static Lazy<HostEntryPoint> Host { get; set; }
public static void Main(string[] args) {
try {
Options = new ProgramOptions();
if (!Parser.Default.ParseArguments(args, Options))
return;
// Root of the program.
// Bootstraps the container then resolves two components.
// One for logging services in the root (this) and the other
// is the *actual* entry point of the application.
Container = new Bootstrapper().CreateContainer();
Log = Container.Resolve<ILog>(TypedParameter.From("boot"));
Host = Container.Resolve<Lazy<HostEntryPoint>>();
if (Options.RunAsService)
RunAsService();
else
RunAsConsole();
} catch (Exception x) {
// Arguably one of the very few places catching a plain
// Exception can make sense: at the root of the program.
Log.FatalException("Unexpected error occurred whilst starting.", x);
Environment.Exit(100);
}
Log.Info("Exiting...");
Container.Dispose();
Thread.Sleep(500);
}
// ... cut for brevity ...
}
internal class Bootstrapper {
public virtual IEnumerable<IModule> GetModules() {
yield return new LoggingModule {
Console = LoggingMode.TraceOrAbove,
File = LoggingMode.WarningOrAbove,
Debug = LoggingMode.Off,
RegisterNetFxTraceListener = true
// Container Modules are an excellent place to pass in
// certain configuration/runtime parameters and options.
// I prefer to "hard code" things like this until there
// is a *real* need to expose such things to a config file,
// and hence the user of the application.
};
// These modules can be specified in any order.
// Container will resolve the object graph at
// build-time not at registration-time.
yield return new QueuesModule() { ConcurrentReceivers = 4 };
yield return new DispatchersModule();
yield return new HciCommandsModule();
yield return new MefModulesModule();
yield return new AzureDataModule() { ConnectionString = "<goes here>"};
}
public virtual void RegisterCore(ContainerBuilder builder) {
builder.Register(c =>
new HostEntryPoint(
c.Resolve<MefModuleLogging>(),
c.Resolve<IEnumerable<IQueueAgent>>(),
c.Resolve<IEnumerable<IDispatcher>>()))
.SingleInstance();
// As well as typically only ever using constructor injection...
// I prefer to explicitly define the dependency resolutions here, each time.
// That is, in my opinion, half the point of IoC. You're doing it to keep
// very close tabs on your dependency graphs. So it should certainly not
// be the norm that you let the container resolve them through its automagicness.
// An exception to this rule is dynamically loaded modules (such as MEF assemblies)
// where you cannot possibly know, at compile-time, what dependencies are required.
}
public IContainer CreateContainer() {
var builder = new ContainerBuilder();
foreach (var module in GetModules())
builder.RegisterModule(module);
RegisterCore(builder);
return builder.Build();
}
}