For our sample app, we’ll define a class that writes the current date out. However, we don’t want it tied to the Console because we want to be able to test the class later or use it in a place where the console isn’t available.

We’ll also go as far as allowing the mechanism writing the date to be abstracted, so if we want to, later, swap in a version that writes tomorrow’s date, it’ll be a snap.

We’ll do something like this:

usingSystem;namespaceDemoApp{// This interface helps decouple the concept of// "writing output" from the Console class. We// don't really "care" how the Write operation// happens, just that we can write.publicinterfaceIOutput{voidWrite(stringcontent);}// This implementation of the IOutput interface// is actually how we write to the Console. Technically// we could also implement IOutput to write to Debug// or Trace... or anywhere else.publicclassConsoleOutput:IOutput{publicvoidWrite(stringcontent){Console.WriteLine(content);}}// This interface decouples the notion of writing// a date from the actual mechanism that performs// the writing. Like with IOutput, the process// is abstracted behind an interface.publicinterfaceIDateWriter{voidWriteDate();}// This TodayWriter is where it all comes together.// Notice it takes a constructor parameter of type// IOutput - that lets the writer write to anywhere// based on the implementation. Further, it implements// WriteDate such that today's date is written out;// you could have one that writes in a different format// or a different date.publicclassTodayWriter:IDateWriter{privateIOutput_output;publicTodayWriter(IOutputoutput){this._output=output;}publicvoidWriteDate(){this._output.Write(DateTime.Today.ToShortDateString());}}}

Now that we have a reasonably structured (if contrived) set of dependencies, let’s get Autofac in the mix!

At application startup, you need to create a ContainerBuilder and register your components with it. A component is an expression, .NET type, or other bit of code that exposes one or more services and can take in other dependencies.

In simple terms, think about a .NET type that implements an interface, like this:

publicclassSomeType:IService{}

You could address that type in one of two ways:

As the type itself, SomeType

As the interface, an IService

In this case, the component is SomeType and the services it exposes are SomeType and IService.

In Autofac, you’d register that with a ContainerBuilder something like this:

// Create your builder.varbuilder=newContainerBuilder();// Usually you're only interested in exposing the type// via its interface:builder.RegisterType<SomeType>().As<IService>();// However, if you want BOTH services (not as common)// you can say so:builder.RegisterType<SomeType>().AsSelf().As<IService>();

For our sample app, we need to register all of our components (classes) and expose their services (interfaces) so things can get wired up nicely.

We also need to store the container so it can be used to resolve types later.

usingSystem;usingAutofac;namespaceDemoApp{publicclassProgram{privatestaticIContainerContainer{get;set;}staticvoidMain(string[]args){varbuilder=newContainerBuilder();builder.RegisterType<ConsoleOutput>().As<IOutput>();builder.RegisterType<TodayWriter>().As<IDateWriter>();Container=builder.Build();// The WriteDate method is where we'll make use// of our dependency injection. We'll define that// in a bit.WriteDate();}}}

Now we have a container with all of the components registered and they’re exposing the proper services. Let’s make use of it.

During application execution, you’ll need to make use of the components you registered. You do this by resolving them from a lifetime scope.

The container itself is a lifetime scope, and you can technically just resolve things right from the container. It is not recommended to resolve from the container directly, however.

When you resolve a component, depending on the instance scope you define, a new instance of the object gets created. (Resolving a component is roughly equivalent to calling “new” to instantiate a class. That’s really, really oversimplifying it, but from an analogy perspective it’s fine.) Some components may need to be disposed (like they implement IDisposable) - Autofac can handle disposing those components for you when the lifetime scope is disposed.

However, the container lives for the lifetime of your application. If you resolve a lot of stuff directly from the container, you may end up with a lot of things hanging around waiting to be disposed. That’s not good (and you may see a “memory leak” doing that).

Instead, create a child lifetime scope from the container and resolve from that. When you’re done resolving components, dispose of the child scope and everything gets cleaned up for you.

(When you’re working with the Autofac integration libraries, this child scope creation is largely done for you so you don’t have to think about it.)

For our sample app, we’ll implement the “WriteDate” method to get the writer from a scope and dispose of the scope when we’re done.

namespaceDemoApp{publicclassProgram{privatestaticIContainerContainer{get;set;}staticvoidMain(string[]args){// ...the stuff you saw earlier...}publicstaticvoidWriteDate(){// Create the scope, resolve your IDateWriter,// use it, then dispose of the scope.using(varscope=Container.BeginLifetimeScope()){varwriter=scope.Resolve<IDateWriter>();writer.WriteDate();}}}}

Now when you run your program…

The “WriteDate” method asks Autofac for an IDateWriter.

Autofac sees that IDateWriter maps to TodayWriter so starts creating a TodayWriter.

Autofac sees that the TodayWriter needs an IOutput in its constructor.

Autofac sees that IOutput maps to ConsoleOutput so creates a new ConsoleOutput instance.

Autofac uses the new ConsoleOutput instance to finish constructing the TodayWriter.

Autofac returns the fully-constructed TodayWriter for “WriteDate” to consume.

Later, if you want your application to write a different date, you could implement a different IDateWriter and then change the registration at app startup. You don’t have to change any other classes. Yay, inversion of control!

Note: generally speaking, service location is largely considered an anti-pattern(see article). That is, manually creating scopes everywhere and sprinkling use of the container through your code is not necessarily the best way to go. Using the Autofac integration libraries you usually won’t have to do what we did in the sample app above. Instead, things get resolved from a central, “top level” location in the application and manual resolution is rare. Of course, how you design your app is up to you.