Friday, July 16, 2010

Autofac Part 3 - Module registration and event handlers

This time we take a look at registration using modules, and using the event handlers provided by Autofac.

Registration using modules
Registration using modules allows more flexibility, reduced complexity, allows configuration parameters to be explicit and better abstraction and type safety.

To use module you have to create a class, which inherits from Autofac.Module and overrides the Load method, fx.:
class ModuleReg : Module
{
  protected override void Load(ContainerBuilder builder)
  {
    base.Load(builder);
    builder.RegisterType<object>();
  }
}
To register a module the following are done:
var builder = new ContainerBuilder();
builder.RegisterModule(new ModuleReg());
var container = builder.Build();
Now you can get all instances, types and everything else registered in the module, resolved just as normal. Modules can register anything you can outside a module, for example you can register more modules.

Modules can are more dynamic as you can set properties and such to indicate different scenarios. More information about module registration can be found here

Autofac events
There are a couple for events which can be handled. These event as described below.
Preparing
Fired before the activation process to allow parameters to be changed or an alternative instance to be provided.
Activating
Fires after the construction of an instance but before it is shared with any other or any members invoked on it.
Activated
Fire when the activation process for a new instance is complete.
Registered
Information about the occurrence of a component being registered with a container.
All events can be handlede by using the methods provided when registering something.
builder.RegisterType<object>().OnPreparing(somedelegate);
builder.RegisterType<object>().OnActivated(somedelegate);
builder.RegisterType<object>().OnActivating(somedelegate);
builder.RegisterType<object>().OnRegistered(somedelegate);
Multiple events can be handled like this:
builder.RegisterType<object>().OnPreparing(somedelegate)
  .OnActivated(somedelegate);
These events are poorly documented, so here is a quick intro. The OnPreparing method, takes this parameter:
Action<PreparingEventArgs>
And you can changed the instance parameters like this:
IEnumerable<Parameter> parameters = new Parameter[] { new NamedParameter("n", 1) };
builder.RegisterType<object>().OnPreparing(e => e.Parameters = parameters);
The OnActivating method take this parameter:
Action<IActivatingEventArgs<TLimit>>
And you can change the instance provided like this:
builder.RegisterType<object>().OnActivation(e => e.ReplaceInstance(new object());
The OnActivated method take this parameter:
Action<IActivatedEventArgs<TLimit>>
And you can use the instance provided like this:
builder.RegisterType<object>().OnActivated(e => e.Instance.Method());
And at last the OnRegistered method, which takes this parameters:
Action<ComponentRegisteredEventArgs>
In my opinion this event aren't very useful, but it is still included here for completeness. You can only get the ComponentRegistry and the ComponentRegistration from this event.
builder.RegisterType<object>().OnRegistered(e =>
  {
    registry = e.ComponentRegistry;
    cr = e.ComponentRegistration;
  });

Thursday, July 1, 2010

Autofac Part 2 - Ordering, Keyed, Named & Metadata Registration

As promised we are going to look into registration ordering, keyed and name registration and registration with metadata.

Registration ordering
When you register something ordering are by default preserved, meaning that the last registration are returned when resolving.
var builder = new ContainerBuilder();
object inst1 = new object();
object inst2 = new object();
builder.RegisterInstance(inst1);
builder.RegisterInstance(inst2);
object resolved = builder.Build().Resolve<object>();
// Here resolved are the same instance as inst2
If you want another behavior it can be done the following way:
object inst1 = new object();
object inst2 = new object();
builder.RegisterInstance(inst1);
builder.RegisterInstance(inst2).PreserveExistingDefaults();
object resolved = builder.Build().Resolve<object>();
// Here resolved are the same instance as inst1
Named and keyed registration
Named and keyed registration are a very handy feature, which allow you to have multiple instances of the same object return if different situations. Here is an example for named registration:
string name = "object.registration";
var cb = new ContainerBuilder();
cb.RegisterType<object>().Named<object>(name);
var c = cb.Build();
object o1 = c.Resolve<object>(name);
// But this will fail unless an registration has been made without
// a name
o1 = c.Resolve<object>();
Keyed registration are basically done the same way:
object key = new object();
var cb = new ContainerBuilder();
cb.RegisterType<object>().Keyed<object>(key);
var c = cb.Build();
object o1 = c.Resolve<object>(key);
// But this will fail unless an registration has been made without
// a key
o1 = c.Resolve<object>();
You are free to mix normal, named and keyed registration as you want, which gives you a lot of flexibility.
Registration with metadata
Metadata allows you to place extra information alongside a registration.
var p1 = new KeyValuePair<string, object>("p1", "p1Value");
var p2 = new KeyValuePair<string, object>("p2", "p2Value");
var builder = new ContainerBuilder();
builder.RegisterType<object>()
    .WithMetadata(p1.Key, p1.Value)
    .WithMetadata(p2.Key, p2.Value);
var container = builder.Build();

Meta<object> objectWithMetadata = container.Resolve<Meta<object>>();
// The metadata can now be accessed through
// objectWithMetadata.Metadata
// The resolved instance can be accessed through
// objectWithMetadata.Value

In the next part I'll look into module registration and using the event handlers provided when registering and resolving.