Introducing Autofac 2.1 RTW
After nearly two years of experimentation, design and development, Autofac’s second major release is here!
Autofac 2.1 is still the IoC container you know and love, but reorganised so that Autofac 1.4’s strengths – especially in providing a low-friction developer experience – really shine.
You can download the binaries here, or read on for some of the feature highlights.
Component Discovery
Otherwise known as convention-driven registration or scanning, Autofac 2 can register a set of types from an assembly according to user-specified rules:
var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
The registration syntax for RegisterAssemblyTypes()
is a superset of the registration syntax for single types, so methods like As<T>()
all work with assemblies as well, and there’s very little extra API to learn.
Relationship Types
When working with IoC you frequently hear advice against passing the container around or resolving components from it directly. Where dynamic relationships are concerned, for example deferred creation, selection from alternatives or parameterisation, there has historically been very little guidance on the alternatives.
Autofac addresses this by automatically supporting small, focused, strongly-typed wrappers that express dynamic dependencies.
For example, instead of calling IContainer.Resolve<IDownloader>()
, a WebCrawler
component that needs to create instances of a downloader on-the-fly can take a dependency on Func<IDownloader>
and the container will provide it automatically so long as IDownloader
is registered.
class WebCrawler : IWebCrawler
{
Func<Uri, IDownloader> _downloaderFactory;
public WebCrawler (Func<Uri, IDownloader> downloaderFactory)
{
_downloaderFactory = downloaderFactory;
}
public void Crawl()
{
var downloader = _downloaderFactory(new Uri("https://autofac.org"));
foreach (var link in downloader.OutboundLinks)
// ...
}
}
As the example shows, you can pass parameters (in this case a Uri) that will be forwarded to the target component’s constructor.
Autofac 2 supports an extensive vocabulary of relationship types that the container understands and provides automatically based on the other available components.
Relationship | Adapter Type | Meaning |
---|---|---|
A needs a B | None | Dependency |
A needs a B at some point in the future | Lazy<B> |
Delayed instantiation |
A needs a _B until some point in the future | Owned<B> |
Controlled lifetime |
A needs to create instances of B | Func<B> |
Dynamic instantiation |
A provides parameters of types X and Y to B | Func<X,Y,B> |
Parameterisation |
A needs all the kinds of B | IEnumerable<B> |
Enumeration |
A needs to know X about B before using it | Meta<B,X> |
Metadata interrogation |
For more information on relationship types, see the introductory article.
Component Metadata
If you’re familiar with the Managed Extensibility Framework (MEF) you have probably seen examples using component metadata.
Autofac uses the underlying support in .NET 4.0 to provide similar functionality. Metadata is associated with a component either in code:
builder.Register(c => new ScreenAppender())
.As<ILogAppender>()
.WithMetadata("AppenderName", "screen");
Or in XML:
<component
type="MyApp.Components.Logging.ScreenAppender, MyApp"
service="MyApp.Services.Logging.ILogAppender, MyApp" >
<metadata>
<item name="AppenderName" value="screen" type="System.String" />
</metadata>
</component>
Unlike a regular property, a metadata item can be queried and used without requiring an instance of the component to be created.
This makes it useful when selecting one of many components based on runtime criteria; or, where the metadata isn’t intrinsic to the component implementation. Metadata could represent the time that an ITask
should run, or the button caption for an ICommand
.
Other components can consume metadata using the System.Lazy<T,TMetadata>
type.
public class Log
{
readonly IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> _appenders;
public Log(IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> appenders)
{
_appenders = appenders;
}
public void Write(string destination, string message)
{
var appender = _appenders.First(a => a.Metadata.AppenderName == destination);
appender.Value.Write(message);
}
}
In .NET 3.5 (as well as 4.0) Autofac 2 provides the weakly typed Meta<T>
class for consuming metadata as a dictionary.
Managed Extensibilty Framework Integration
MEF introduces a standard API for creating extensible applications in .NET 4.0. If your Autofac-based application has extensibility points, plugin developers can use the MEF attributes to mark up their extensions, while internally they can be hosted in the Autofac container just like any other Autofac component.
Any MEF catalog type can be registered directly with the container, so to use MEF’s directory scanning ability for example, a System.ComponentModel.Composition.DirectoryCatalog
can be used.
var catalog = new DirectoryCatalog("Extensions");
builder.RegisterComposablePartCatalog(catalog);
For documentation on this API see the Autofac MEF integration wiki page.
There’s a deeper discussion of the underlying architecture here.
Other Improvements
Although Autofac 2 introduces some new features, a lot more work went into making the core architecture and API of Autofac more consistent, robust and explicit.
To list a very small selection:
-
Generic type constraints are now respected - Autofac won’t try to use unsuitable generic types when resolving references to generic services.
-
The instance parameters to activation events are strongly-typed, for example
builder.RegisterType<Foo>().OnActivating(e => e.Instance.Start())
. -
ASP.NET MVC controller registration is more flexible and simpler via the
RegisterControllers()
method. -
Non-shared (‘factory’) scope is the default, rather than Singleton.
-
“Resolve Anything” support
-
API documentation is seachable on Google.
Upgrading from Autofac 1.4
If you’re upgrading from an earlier Autofac release, see the New in V2 wiki page for more detailed information.
There are many breaking changes for users of Autofac 1.4 who want to upgrade. Most of these are just name changes, but some less commonly-used features will cause non-trivial rework. This is the price of keeping Autofac clean, supportable and relevant - if you’re affected by breaking changes you can find consolation in knowing that Autofac is not on the path to becoming a legacy framework :).
If things do get tough, help is only ever an email away.
Where to Next?
The 2.1 release is largely foundational – its focus is on improving the core container. There are plenty of new features in it, but next in the pipeline is a 2.2 version including, for example, broader ASP.NET MVC support and no doubt some fixes and improvements based on learnings from 2.1.
Acknowledgements and Thanks
Autofac 2 draws on many inspirations and input from a large community. Direct credit for Autofac 2 belongs to the project members, contributors to the mailing list, and supporters in the blogosphere, on stackoverflow and on Twitter.
Many of the ideas in Autofac 2, just as with the version before it, derive from other projects like Windsor, MEF, Funq, Unity, Ninject, StructureMap and their precursors.
Extra thanks is due to the MEF team, whose tireless work is making the .NET a friendlier place for IoC every day.