Registration sources are great when you don’t have a finite set of registrations you can add to a container. Many times, assembly scanning and/or use of modules can address dynamic registration concerns… but when all else fails or those means don’t accomplish what you’re looking to do, a registration source may be the way to go.

The AnyConcreteTypeNotAlreadyRegisteredSource, or “ACTNARS” as we call it, is an example of a registration source that Autofac ships with that allows you to resolve any concrete type from the Autofac container regardless of whether or not you specifically registered it. People moving from other inversion-of-control containers may be used to this sort of behavior, so ACTNARS is a way to bridge that gap.

You can use the Autofac.Features.ResolveAnything.AnyConcreteTypeNotAlreadyRegisteredSource by adding it to your container.

The best way to show how to implement a registration source is through a simple example.

Let’s say you have a factory that is responsible for generating some sort of event handler class. You need to generate them through the factory rather than through Autofac, so you don’t have the handlers themselves registered with Autofac. At the same time, there’s not a good way to say “when a person asks for any event handler, generate it through this special factory.” This is a great example of where a registration source can come in handy.

For the example, let’s define a simple event handler base/abstract class and a couple of implementations.

Now that we have the services and the consumers, let’s make a registration source. In the example source, we’ll…

Determine if the resolve operation is asking for a BaseHandler type or not. If it’s not, the source won’t provide any registration to satisfy the resolve request.

Build up the dynamic registration for the specific type of BaseHandler derivative being requested, which will include the lambda that invokes the provider/factory to get the instance.

Return the dynamic registration to the resolve operation so it can do the work.

Here’s the code for the registration source.

usingAutofac;usingAutofac.Core;usingAutofac.Core.Activators.Delegate;usingAutofac.Core.Lifetime;usingAutofac.Core.Registration;publicclassHandlerRegistrationSource:IRegistrationSource{publicIEnumerable<IComponentRegistration>RegistrationsFor(Serviceservice,Func<Service,IEnumerable<IComponentRegistration>>registrationAccessor){varswt=serviceasIServiceWithType;if(swt==null||!typeof(BaseHandler).IsAssignableFrom(swt.ServiceType)){// It's not a request for the base handler type, so skip it.returnEnumerable.Empty<IComponentRegistration>();}// This is where the magic happens!varregistration=newComponentRegistration(Guid.NewGuid(),newDelegateActivator(swt.ServiceType,(c,p)=>{// In this example, the factory itself is assumed to be registered// with Autofac, so we can resolve the factory. If you want to hard// code the factory here, you can do that, too.varprovider=c.Resolve<IHandlerFactory>();// Our factory interface is generic, so we have to use a bit of// reflection to make the call.varmethod=provider.GetType().GetMethod("GetHandler").MakeGenericMethod(swt.ServiceType);// In the end, return the object from the factory.returnmethod.Invoke(provider,null);}),newCurrentScopeLifetime(),InstanceSharing.None,InstanceOwnership.OwnedByLifetimeScope,new[]{service},newDictionary<string,object>());returnnewIComponentRegistration[]{registration};}publicboolIsAdapterForIndividualComponents{get{returnfalse;}}}

The last step is to register everything with Autofac - the registration source, the factory, and the consuming classes. Notice, though, that we don’t have to register the actual handlers themselves because the registration source takes care of that.