Autofac Project Status Update

Autofac 2.4 Coming Soon

Sometime early in the New Year we’ll be releasing a new version of Autofac.

The star of the show in Autofac 2.4 is a much revamped ASP.NET MVC implementation by Alex Meyer-Gleaves, optimised for use with the MVC3 release. This promises a much quicker, simpler and more robust setup process, finally ridding us of the dependency on an HTTP module (Web.config change) for lifetime control.

Also included in Autofac 2.4 is support for decorators, including some pretty sophisticated coverage of open generic decorator scenarios. In earlier versions of Autofac the very useful Decorator pattern could be a little awkward to implement – I’ll be writing more soon about how Autofac 2.4 tidies this up.

Finally, the new release will continue our recent efforts to improve error messages and bring more consistency and completeness to the APIs introduced in the 2.x series, such as the assembly scanning support. There are no planned breaking changes.

NuGet Packages

Through distribution with ASP.NET MVC3, the NuGet package manager is rapidly gaining traction as the standard way to distribute open source projects for .NET. Thanks to the pioneering efforts of some of the Autofac community there are packages for:

  • Autofac, including its WCF and MEF integrations, for .NET 3.5/4.0 and Silverlight 3/4 (Autofac)
  • Autofac with ASP.NET MVC2 for .NET 3.5/4.0 (Autofac.Mvc2)
  • Autofac with ASP.NET WebForms for .NET 3.5/4.0 (Autofac.Web)

While we expect to fine tune the packages along with the upcoming 2.4 release, you can certainly use NuGet today if you want to use Autofac in your projects.

Open Generics and Autofac 2.3

Autofac 2.3 hit the shelves more than three months ago but as it coincided pretty closely with the birth of our daughter Vera I didn’t write much about it at the time.

One improvement worth mentioning is the much-expanded support for open generic components, contributed by Rikard Pavelic. I answered a recent question on the Autofac mailing list with “it can’t be done” only to find later that the scenario being discussed was already supported. Though fairly unusual, it is an interesting feature so I’ll describe it below, but first the less exotic cases.

Generic Parameter Constraints

C# allows the arguments of a generic type to apply constraints that parameters must match. For example, we might constrain an event handler implementation to a type of event:

interface IEventHandler<in TEvent> {
    void Handle(TEvent @event);
}

In this small example we have an interface that helps us dispatch event objects to handlers. Typically there would be one or more handlers for each event type, most of them specific to the kind of event. We also have a marker interface for events that should trigger some kind of auditing, and a handler that will make this happen.

interface IAuditableEvent { }

class AuditingEventHandler<TEvent> : IEventHandler<TEvent>
        where TEvent : IAuditableEvent {
    void Handle(TEvent @event) {
       // Write an audit record…
    }
}

Note that the handler uses a generic type constraint to select the kind of events it is interested in. Some events will be auditable, others not:

class ItemAddedToCartEvent { }

class CheckoutCompletedEvent : IAuditableEvent { }

The AuditingEventHandler<TEvent> will be registered as an open generic type.

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(AuditingEventHandler<>))
    .As(typeof(IEventHandler<>));
var container = builder.Build();

Assuming that we’ve registered all of the different event handlers for the above two events, what should happen when we resolve all of the handlers for ItemAddedToCartEvent?

var handlers = container.Resolve<IEnumerable<IEventHandler<ItemAddedToCartEvent>>>();

The AuditingEventHandler<TEvent> component is registered to provide the IEventHandler<TEvent> service, but the generic type constraint doesn’t match. In earlier versions of Autofac, the above line would have raised an exception.

With support for open generic parameter constraints, Autofac will now instantiate only the types whose constraints match, so the handlers collection above would be returned successfully without any attempt to instantiate the AuditingEventHandler<TEvent>.

If instead an auditable event is to be handled, then the auditing handler would be included:

// Succeeds and returns an AuditingEventHandler<CheckoutCompletedEvent>
var handlers = container.Resolve<IEnumerable<IEventHandler<CheckoutCompletedEvent>>>();

Constraint Types

Autofac 2.3 handles all of the generic parameter constraints you’re likely to encounter, including:

  • new()
  • class and struct
  • Base type and implemented interfaces

Parameter Binding Solver

Open generic types are more subtle and complicated to support than they sometimes appear. Take this contrived but not unimaginable example:

class MonoDictionary<T> : IDictionary<T,T> { }

The generic parameter T appears twice in the parameter list of the implemented IDictionary<TKey,TValue>! That means if we register MonoDictionary<T>:

builder.RegisterGeneric(typeof(MonoDictionary<>))
    .As(typeof(IDictionary<,>));

Then we should be able to resolve IDictionary<int,int> but not IDictionary<int,string>. Tricky – but as of version 2.3, Autofac can handle it.

The example we discussed on the Autofac mailing list was something like:

interface IProducer<T> { }

class NullableProducer<T> : IProducer<T?>
    where T : struct { }

The twist here is that the generic component NullableProducer<T> does not parameterise IProducer<T> directly with T, but rather Nullable<T> (abbreviated to T?).

This means that if we resolve IProducer<int?> then NullableProducer<int> should be activated, while resolving IProducer<int> should ignore NullableProducer<T> altogether.

Autofac 2.3 also supports this case, with some terse but surprisingly succinct code. Hopefully this will open up some new, richer generic component possibilities.