Blair Conrad

How to completely disable Autofac components

This week I started working with the Autofac Inversion of Control container at the Day Job. The first project I tried to introduce Autofac to needed a plugin system. I figured this was a perfect use of Autofac's implicit relationship handlers. Sure enough, a

container.Resolve<IEnumerable<IPlugin>>()

did the trick - I got a nice list of plugin instances for the application to use.

This isn't enough, though. We need to disable certain components via configuration. One option would be to remove the components from the configuration file, but I wanted to make it easy to restore the plugins (and their original configuration) should the need arise. After poring over the Autofac documentation, it seemed like adding an "Enabled" flag in the components' metadata would be the best way to handle toggling them between on and off.

Setting up the config file was straightforward,

<autofac defaultAssembly="DisableComponents">
  <components>
    <component type="DisableComponents.Plugin1" service="DisableComponents.IPlugin">
      <metadata>
        <item name="Enabled" value="false" type="System.Boolean" />
      </metadata>
    </component>
    <component type="DisableComponents.Plugin2" service="DisableComponents.IPlugin">
      <metadata>
        <item name="Enabled" value="true" type="System.Boolean" />
      </metadata>
    </component>
  </components>
</autofac>

as was filtering the components list.

var enabledComponents = container.Resolve<IEnumerable<Meta<IPlugin>>>()
    .Where(ComponentIsEnabled)
    .Select(c=>c.Value);

...

private static bool ComponentIsEnabled<T>(Meta<T> component)
{
    const string enabled = "Enabled";
    return !component.Metadata.ContainsKey(enabled) || (bool)component.Metadata[enabled];
}

They're still created, though

This approach worked, but all all components are instantiated, including the disabled ones which are made just so we can throw them away. This seems a little wasteful. Worse, a particular installation may have a plugin disabled because it can't (or doesn't want to) support its creation. So I sought a way to prevent the instantiation of the unwanted plugins.

I tried to find a way to remove or disallow registration based on the metadata, or to intercept component creation, but came up short. The best I could come up with was a modification to the approach above:

var enabledComponents = container.Resolve<IEnumerable<Meta<Func<IPlugin>>>>()
    .Where(ComponentIsEnabled)
    .Select(c=>c.Value());

(I would have preferred to use a Lazy over a Func, but I'm working with .Net 35.)

This works—the plugins are only created when they're enabled—but it feels inelegant. I can't help but think that my Autofac knowledge is too shallow to have discovered the "right" way to do this. Hopefully deeper understanding will come in time…