My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
NewInV2  
Upgrade help for users of Autofac 1.x
Autofac2
Updated Aug 6, 2010 by nicholas...@gmail.com

Introduction

Autofac 2.x introduces some significant changes with the aim of simplifying and streamlining Autofac usage. This page highlights the most important changes for Autofac 1.x users.

For an overview of the new features for new users, see http://nblumhardt.com/2010/04/introducing-autofac-2-1-rtw/ and http://nblumhardt.com/2010/05/autofac-2-2-released/.

Namespace Changes

Most namespaces have been updated to fit a scheme that should keep things more organised and easier to find.

The biggest change is that the Autofac.Builder namespace has been moved into Autofac, and an additional namespace Autofac.Core created to hold types that are less-frequently used.

Most applications can now be built using the Autofac namespace only. New users will find this namespace easier to explore, as only the types relating to the most common scenarios are there.

Builder Syntax Changes

Separation of Registration Overloads

Whereas previously the type/delegate/instance registration methods were all called Register(), these have now been given distinct names. Only delegates can be registered with the Register() method, other registration types are more explicit:

builder.Register(c => new Plane());
builder.Register<Car>();
builder.Register(new Boat());

Becomes:

builder.Register(c => new Plane()); // Unchanged
builder.RegisterType<Car>();
builder.RegisterInstance(new Boat());

This change makes the available functionality easier to find in IntelliSense(TM), as well as bringing consistency with other methods like RegisterGeneric(), RegisterModule() etc.

Non-Shared ('Factory') Components by Default

The default lifetime in Autofac 1 is 'singleton'. In Autofac 2, components default to 'factory'.

New Lifetime/Sharing Terminology

The names for lifetime/sharing configuration have been changed to reflect changes in the underlying architecture, and to remove common sources of confusion.

Old Autofac 1 Name New Autofac 2 Name Notes
SingletonScoped SingleInstance Removes confusion with the Singleton pattern
FactoryScoped InstancePerDependency Removes confusion with the Factory pattern and other features
ContainerScoped InstancePerLifetimeScope
InContext InstancePerMatchingLifetimeScope

Strongly-typed Activation Events

The OnActivating configuration method now has a strongly-typed parameter:

builder.RegisterType<Connection>().OnActivating(c => c.Open());

Adding to an Existing Container

In Autofac 1.x registraitons can be added to an existing container with ContainerBuilder.Build(IContainer).

In Autofac 2, registrations are added when creating a new lifetime scope:

var container = ...
using (var lifetime = container.BeginLifetimeScope(builder =>
{
   builder.RegisterType<X>();
   builder.RegisterType<Y>();
}))
{
   lifetime.Resolve<X>() //....
}

For changes to an existing container, use ContainerBuilder.Update():

var container = // something already built

var updater = new ContainerBuilder();
updater.RegisterType<A>();
updater.Register(c => new B()).As<IB>();

// Add the registrations to the container
updater.Update(container);

Configuration this way is often much harder to follow than a simple "register then build" style, so again, use this feature only where necessary.

Other Syntax Changes

  • DefaultOnly has been renamed PreserveDefaults
  • OnlyIf has been removed; the RegisterCallback method now provides this ability

Lifetime and Scope

Autofac 2 is more explicit about the role of nesting in lifetime.

Instead of creating nested containers with CreateInnerContainer(), as in:

using (var requestContainer = container.CreateInnerContainer())
{
}

An ILifetimeScope object is now created using BeginLifetimeScope():

using (var requestScope = container.BeginLifetimeScope())
{
}

Modules Included by Default

Collection Support ("Resolve All")

All instances supporting a particular service can be retrieved by resolving IEnumerable<T> as in:

builder.RegisterType<A1>().As<IA>();
builder.RegisterType<A2>().As<IA>();

var container = builder.Build();

// Contains an instance of both A1 and A2
Assert.AreEqual(2, container.Resolve<IEnumerable<IA>>().Count());

Types can use IEnumerable<T> to declare a dependency, and Autofac 2 will automatically provide all instances as above:

class UsesA
{
  public UsesA(IEnumerable<IA> allAs) { }
}

Auto-Generated Factories

When one component needs to dynamically create instances of another, it can take a dependency on a delegate that returns the type of component it requires:

class UsesServer
{
  Func<IServerConnection> _connectionFactory;

  public UsesServer(Func<IServerConnection> connectionFactory)
  {
    _connectionFactory = connectionFactory;
  }

  public void OnNewWork()
  {
    IServerConnection connection = _connectionFactory();
    // ...
  }
}

No explicit configuration is required to use this feature:

builder.RegisterType<FtpConnection>().As<IServerConnection>();
builder.RegisterType<UsesServer>();

By registering IServerConnection, Autofac 2 will automatically inject delegates that return type IServerConnection.

Owned Instances

Autofac 2 introduces the Owned<T> type, and automatically resolves dependencies of this type for any available services.

A component that needs to dynamically create instances of another component can accept a Func<Owned<T>> to gain this functionality.

A component that gains references to Owned<T> is responsible for calling Owned<T>.Dispose when the instance is no longer required. It is a bug to not clean up owned instances.

Under the hood, an Owned<T> is allocated its own nested lifetime scope, so all of its dependencies will be cleaned up when it is.

Container Instance Ownership Changes

In Autofac 1, weak references are held by the container. This makes sense if the objects being referenced use disposal to release GC/finalizer resources, but if the dispose method contains application logic then GC timing could introduce unexpected behaviour.

Autofac 2 holds normal references. To opt out of this behaviour and mange disposal manually, use the ExternallyOwned registration modifier.

Convention-Based (Data-Driven) Registration

The RegisterAssemblyTypes method provides syntax for declaratively specifying how a set of types is registered:

Assembly controllers = // ...

builder.RegisterAssemblyTypes(controllers)
  .Where(t => t.IsAssignableTo(typeof(IController))
  .Named(t => "controller-" + t.Name.ToLower());

Other syntax elements for lifetime, ownership etc. are available through the same methods as for regular types.

An overloaded version of As allows types to be mapped to the services they provide, and the AsImplementedInterfaces method supports the common convention of having components provide all interfaces they implement.

Changes to Named Services

Named services now require type information as well, and this must match in both the registration and resolution calls:

builder.RegisterType<Foo>().Named<IFoo>("foo");

matches:

container.Resolve<IFoo>("foo");

but not:

container.Resolve<IBar>("foo");

This means that names can now be used with open generic registrations, among other things.

XML Configuration Changes

Separate Assembly for XML Configuration

ConfigurationSettingsReader and related XML configuration support has been moved to Autofac.Configuration.dll

This will allow the XML configuration support to be significantly extended without bloating the core assembly.

It is also a goal of Autofac 2 for the same core assembly (Autofac.dll) to run under both .NET and Silverlight. Moving the System.Configuration-dependent classes, which are not supported on Silverlight, out of the core assembly enables this.

Syntax Changes

Element Names Changed

Autofac 1.x Name Autofac 2 Name
scope instance-scope
ownership instance-ownership
extendedProperties metadata
extendedProperty item

Instance Scope Value Changes

Autofac 1.x Name Autofac 2 Name
factory per-dependency
singleton single-instance
container per-lifetime-scope

Instance Ownership Value Changes

Autofac 1.x Name Autofac 2 Name
scope lifetime-scope

Property Injection Value Changes

Rather than 'none', 'all' and 'unset' the values are now 'yes' or 'no'.

ASP.NET MVC Integration Changes

Autofac 1.4 and earlier 2.1 versions used AutofacControllerModule as a way of finding and registering ASP.NET MVC controllers with the container.

In the Autofac 2.1 MVC integration, there is a new ContainerBuilder extension method called RegisterControllers.

var builder = new ContainerBuilder();

// Was:
// builder.RegisterModule(new AutofacControllerModule(...))
builder.RegisterControllers(Assembly.GetExecutingAssembly());

_containerProvider = new ContainerProvider(builder.Build());
ControllerBuilder.Current.SetControllerFactory(
                new AutofacControllerFactory(_containerProvider));

The reason for the switch is that RegisterControllers is a thin wrapper around the new assembly scanner, and supports the same syntax as the rest of Autofac’s registration methods:

builder.RegisterControllers(assembly)
  .InjectProperties()
  .OnActivated(e => Log.Information("Controller created: " + e.Instance));
Comment by project member vijay.sa...@gmail.com, Nov 15, 2009

The auto-gen'd factories are a great idea. I'm looking forward to implementing

Comment by bryan.murphy, Nov 16, 2009

Looks promising! Keep up the good work!

Comment by DamR...@gmail.com, Nov 18, 2009

I've found that with the new API it is impossible for a Module to get a hold of the container it is acting on. I've spent about 8 hrs on this and still can't see how its possible. Maybe this was a desired feature but in the case of my custom module, I must be able to at some point provide one of my objects the container on which it resides I used to use the Configure method for this but this is no longer supported in V2.

Comment by project member nicholas...@gmail.com, Nov 18, 2009

@DamReev? thanks for the feedback! Components can get access to the container by depending on it, i.e. your object that needs the container can just include IComponentContext (or ILifetimeScope) in its constructor arguments.

Most of the time in Autofac there is a better alternative than working directly with the container - can you give more details of what your object needs to do with it?

Comment by andy...@gmail.com, Nov 23, 2009

This looks like a lot of good stuff. I have a question about Collection Support being included by default. What is the best practice for implementing a Composite pattern then? If I have the following classes:

FooImpl1? : IFoo {}

FooImpl2? : IFoo {}

CompositeFoo? : IFoo {

public CompositeFoo?(IEnumerable<IFoo> childFoos) {}
}

How can I set things up so that FooImpl1? and FooImpl2? are injected into the CompositeFoo? constructor, and CompositeFoo? is registered as the IFoo implementation? Today I do that by using the MemberOf?<IEnumerable<IFoo>>. Will that still work and will that be the preferred method of wiring up a composite?

Comment by project member nicholas...@gmail.com, Nov 23, 2009

@andyalm The new collection support works as a fallback - if you use the member-of style of collection configuration it will override the default behavior, i.e., your example will still work. I'll make sure there is a test case to cover it, thanks very much for raising the point.

Comment by ylw...@gmail.com, Jan 6, 2010

As of 2.1.6, "ContainerBuilder?.Build(IComponentRegistry componentRegistry)" has been marked as "internal" thus prevents us from making registrations inside of a resolved object (since there's no way to assign the "IContainer" generated by a call of ContainerBuilder?.Build(), which the builder is instantiated inside the resolved object, back to main container).

With the approach above, it's possible to do registration + initialization of modules (custom modules, not autofac modules) in one phase, otherwise breaking up the registration and initialization in 2 phases for all module is the only possible solution I can think of, which make the code less elegant.

Is there any other workaround to this problem? Or if it's not a good design, Is there any other better alternative with autofac?

Comment by project member nicholas...@gmail.com, Jan 6, 2010

@ywl633 thanks for raising the point - I've updated the page with "Adding to an Existing Container".

The method you're looking for is an extension IContainer.Configure().

Cheers, Nick

Comment by yuri.mam...@gmail.com, Jan 9, 2010

In Autofac 1.x: "Factory scoped components that are owned by the container are held using weak references". Why these refereces are strong in 2.x?

Comment by project member nicholas...@gmail.com, Jan 9, 2010

@yuri, the Autofac 1 behaviour is find 99% of the time, but it is a possible source of Heisenbugs - program behaviour could become incorrect because of GC timing. In Autofac 2, if you don't want references held, use .ExternallyOwned? when you register a component.

Judging by your other sample, you're in Windows Forms app, where I can see this being tricky. Try resolving forms with the Owned<T> type at the very root of the object graph, thus disposing Owned<T> will dispose the form and anything else it references.

If you have any ideas for making this more friendly please email autofac@googlegroups.com.

Thanks!

Comment by yuri.mam...@gmail.com, Jan 9, 2010

Nick, have no problem with disposing it manually. Just was caught by surprise that splash screen, which I know was disposed and application has no references to it after startup, was disposed again from container dispose at application end.

I believe it is important to clearly state such change in behavior on this page.

Thanks!

Comment by project member nicholas...@gmail.com, Jan 10, 2010

Done, thanks Yuri.

Comment by rikard.p...@gmail.com, Jan 25, 2010

How can we use DynamicProxy? in V2? OnActivating? handler.Instance has only get property, so it is difficult to replace resolved instance with proxy instance.

Thanks!

Comment by project member nicholas...@gmail.com, Jan 26, 2010

@rikard Hi - there's an outstanding issue in the issue tracker (I believe called "update contrib") - getting DP integration back online is the #1 piece of work left. You should expect an update before too long that resolves this problem.

Thanks,

Nick

Comment by project member tysonstolarski@gmail.com, Feb 1, 2010

Looking good Nick!

One question, was there a reason the 'TryResolve?<T>( out T instance )' method was removed? I've simply added my own using an extension method without any difficulties, but was wondering if it was removed for some technical reason?

Cheers. Tyson.

Comment by project member nicholas...@gmail.com, Feb 2, 2010

Tyson, I've raised the missing overload as a bug. You'll be glad to hear that your Configure() issue has already been addressed in the trunk:

var scope = container.BeginLifetimeScope?(builder => {

builder.Register(x); // etc.
});

Needs a little more polish but will be available in the 2.1 RC.

Thanks for the detailed feedback!

Comment by project member tysonstolarski@gmail.com, Feb 2, 2010

Haha I already downloaded the latest source and noticed that Configure overload, thanks! I'll be sure to feedback any bugs, but seems to be working fine so far.

Much nicer way of doing it IMO by the way! Cleaner API and more visible. And also fits with my virtual method on my base classes that takes a ContainerBuilder? parameter for configuration. I dont event need to adapt it with a lambda, just pass the function delegate straight in! :D

Cheers. Tyson.

Comment by joel.mue...@gmail.com, Feb 18, 2010

In 2.1.10.754 there doesn't seem to be an IContainer.Configure method. Am I missing something? It's certainly not part of RegistrationExtensions?. Should I be doing this instead?

module.Configure(container.ComponentRegistry?)

Comment by project member nicholas...@gmail.com, Feb 20, 2010

@joel, in 2.1.10 and onwards a constructed container is configured via BeginLifetimeScope?(builder => xxx).

The best way to configure any container is via the ContainerBuilder? that creates it, if that is possible in your scenario.

Cheers

Comment by joel.mue...@gmail.com, Feb 22, 2010

@nicholas - So you're saying that in v2 there's no way to add registrations to an existing container? Instead, you can only create a new scope that has extra registrations in it? That seems like a step backwards to me, but maybe it will make more sense to me after I've finished rewriting a large amount of code to accommodate this change. In some future version of my software, when I have time to upgrade to Autofac 2.

Comment by rob.eise...@gmail.com, Mar 4, 2010

I'm with joel. I need to be able to add registrations to an existing container without defining a child scope. Is there something I'm missing?

Comment by bwatts@gmail.com, Mar 7, 2010

In v1, I like to use a registration variation which does not use a local variable for registrations. The syntax is:

public class FooModule? : BuilderModule? {

public FooModule?(int someParam) {
Register(new Foo(someParam)).As<IFoo>().SingletonScoped?();

Register<Bar>().As<IBar>().FactoryScoped?();
}

}

The class which enables this is:

public class BuilderModule? : ContainerBuilder?, IModule {

void IModule.Configure(IContainer container) {
Configure(container);
}

protected virtual void Configure(IContainer container) {
Build(container);
}

}

In v2, Build(IComponentRegistry) is internal, so this simple indirection won't work. At first glace, it looks like I could do:

public void Configure(IComponentRegistry componentRegistry) {

var container = Build();

foreach(var registration in container.ComponentRegistry?.Registrations) {
componentRegistry.Register(registration);
}

}

But I don't feel fully confident in that approach, as I don't know if the Registrations property includes registration source information.

How would I enable this in v2?

Comment by bogdan...@gmail.com, Mar 8, 2010

Hello,

I do not see the IComponentDescriptor. How do I get to BestKnownImplementationType? ?

Comment by project member nicholas...@gmail.com, Mar 10, 2010

@bogdanutz, this is now IComponentRegistration.Activator.LimitType?

@bwatts - override ContainerBuilder?.RegisterCallback? and save a collection of callbacks in BuilderModule?. Then, on IModule.Configure, execute each of these callbacks against the provided IComponentRegistry... Voila! :)

Comment by bwatts@gmail.com, Mar 10, 2010

@nicholas.blumhardt - Very nice. Thanks for the tip!

Comment by jesuissur@gmail.com, Mar 15, 2010

I'm with @rob.eisenberg and @joel on the fact it "should be" easier to add new registration afterwards on the same container.

Thanks

Comment by project member nicholas...@gmail.com, May 29, 2010

ContainerBuilder?.Build(IContainer) is again public in Autofac 2, as ContainerBuilder?.Update().


Sign in to add a comment
Powered by Google Project Hosting