Autofac Conditional Registration Support

autofac, dotnet comments edit

Alex and I have been working on deprecating the ability to update an Autofac container after it’s already been built. There are lots of reasons for this, and if you’re curious about that or have feedback on it, we have a discussion issue set up. You can also see ways to work around the need to update the container in that issue, so check it out.

However, one of the main reasons we’ve heard about why people want to update the container is to handle conditional registrations. For example, “I only want ComponentB registered in the container if ComponentA is not registered.”

To that end, in version 4.4.0 we’ve added OnlyIf() and IfNotRegistered() extensions to support conditional registration.

OnlyIf() lets you provide a lambda that acts on an IComponentRegistry. You can check if something is or isn’t registered and have some other registration execute only if the predicate returns true.

IfNotRegistered() is a convenience method built on OnlyIf() that allows you to execute a registration if some other service is not registered.

The documentation has been updated to explain how it works including examples but here’s a taste:

var builder = new ContainerBuilder();

// Only ServiceA will be registered.
// Note the IfNotRegistered takes the SERVICE TYPE to
// check for (the As<T>), NOT the COMPONENT TYPE
// (the RegisterType<T>).
builder.RegisterType<ServiceA>()
       .As<IService>();
builder.RegisterType<ServiceB>()
       .As<IService>()
       .IfNotRegistered(typeof(IService));

// HandlerA WILL be registered - it's running
// BEFORE HandlerB has a chance to be registered
// so the IfNotRegistered check won't find it.
//
// HandlerC will NOT be registered because it
// runs AFTER HandlerB. Note it can check for
// the type "HandlerB" because HandlerB registered
// AsSelf() not just As<IHandler>(). Again,
// IfNotRegistered can only check for "As"
// types.
builder.RegisterType<HandlerA>()
       .AsSelf()
       .As<IHandler>()
       .IfNotRegistered(typeof(HandlerB));
builder.RegisterType<HandlerB>()
       .AsSelf()
       .As<IHandler>();
builder.RegisterType<HandlerC>()
       .AsSelf()
       .As<IHandler>()
       .IfNotRegistered(typeof(HandlerB));

// Manager will be registered because both an IService
// and HandlerB are registered. The OnlyIf predicate
// can allow a lot more flexibility.
builder.RegisterType<Manager>()
       .As<IManager>()
       .OnlyIf(reg =>
         reg.IsRegistered(new TypedService(typeof(IService))) &&
         reg.IsRegistered(new TypedService(typeof(HandlerB))));

// This is when the conditionals actually run. Again,
// they run in the order the registrations were added
// to the ContainerBuilder.
var container = builder.Build();

If that’s something you’re into, head over to NuGet, grab v4.4.0 of Autofac, and try it out. Find something not working? Let us know!

Comments