Resolve Anything

Ward Bell, one of the most diligently pragmatic programmers out there, just wrote about bootstrapping Prism with containers other than Unity.

One of the pain points that Ward observes is Prism’s use of “resolve anything” – a Unity feature that causes the container to act as though all concrete types are registered.

// Works, even though Foo isn't registered,
// because Foo is concrete.
var container = new UnityContainer();
var foo = container.Resolve<Foo>();

Other containers have different behaivours – by default, Autofac will throw ComponentNotRegisteredException in this case.

I’m not a fan of Unity’s behaviour – I rarely use concrete types as services, and generally would want to configure them first anyway.

However, for those with different views, there are simple ways to make this work with Autofac.

Autofac 1.4 – RegisterTypesMatching()

Autofac 1.4 includes a configuration method that can help here. The parameter is a predicate on a requested Type, and if the result is true the container will happily resolve instances of the type.

var builder = new ContainerBuilder();
builder.RegisterTypesMatching(t => t.IsClass && !t.IsAbstract);
var container = builder.Build();

// Now works
var foo = container.Resolve<Foo>();

Autofac 2.1 – ResolveAnythingSource

Autofac 2 doesn’t have an equivalent to RegisterTypesMatching(). This is because Autofac 2’s assembly scanner, RegisterAssemblyTypes() does a much better job in similar scenarios.

Those who’ve been following along with this blog lately will have seen how registration sources provide a simple way to extend the container to understand new component types (like Lazy Dependencies.)

Well, the registration source to implement “resolve anything” is just a few lines, included here in its entirety. If you need this behaviour, feel free to include it in your project.

class ResolveAnythingSource : IRegistrationSource
{
    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service,
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        var ts = service as TypedService;
        if (ts != null && !ts.ServiceType.IsAbstract && ts.ServiceType.IsClass)
        {
            var rb = RegistrationBuilder.ForType(ts.ServiceType);
            return new[] { RegistrationBuilder.CreateRegistration(rb) };
        }

        return Enumerable.Empty<IComponentRegistration>();
    }
}

Configuring the container to use the new source is easy.

var builder = new ContainerBuilder();
builder.RegisterSource(new ResolveAnythingSource());
var container = builder.Build();

// Works now
var foo = container.Resolve<Foo>();

One Small Caveat

You should probably be aware of one small gotcha that both of these samples exhibit. If you actually do register an implementation of Foo, then resolve all instances of Foo, you’ll find that both your registered component, plus the automatically-generated one, will be there. This is a very unlikely situation, but it might pay to keep it in mind.

If you found your way here looking for Autofac’s Prism integration, good news is right around the corner! The source for AutofacContrib.Prism is in the trunk, and just needs a few updates before it will get a proper release.

  • I’ve hit the same pain points with Prism and an early version of Ninject which used Singleton as default. Since the UnityBootstrapper doesn’t register some types, they were being registered automatically and then turned into Silngletons. It’s nice to know Autofac has an easy way to solve these problems.

  • Pingback: Dew Drop – January 3, 2009 | Alvin Ashcraft's Morning Dew()

  • I’m with you on this – Resolving things you didn’t register is IMO a bug and it surprises me that people actually do request that (perhaps only these who have been using Unity for some time and then move to AutoFac or any other container (cough Windsor cough)).

    the IRegistrationSource looks quite similar to something I’ve already seen somewhere http://devlicio.us/blogs/krzysztof_kozmic/archive/2009/11/16/castle-windsor-lazy-loading.aspx 🙂

    Not sure it behaves like ILazyComponentLoader, which is questioned only if there’s no component registered already.

  • Glad this is going in the right direction then 🙂

    Krzysztof, the IRegistrationSource implementation in Autofac 1.x had the behaviour you describe; in 2.1, sources are always included regardless of other registered implementations.

  • Since postiing this article I’ve talked to a few people from WPF land, where this behaviour is more useful. You’ll find AnyConcreteTypeNotAlreadyRegisteredSource (yes it could use renaming) in the Autofac.Features.ResolveAnything namespace in builds 2.1.7 and onwards.

  • Pingback: Introducing Autofac 2.1 RTW : Nicholas Blumhardt()

  • Pingback: Autofac正式发布2.1版 - 自由、创新、研究、探索 - 博客园()