23

Something along those lines:

builder.RegisterType<MyType>().As<IType>();
builder.RegisterType<MyType2>().As<IType>();
builder.DeRegisterType<MyType>().As<IType>()

var container = builder.Build();
var types = container.Resolve<IEnumerable<IType>>();
Assert.IsTrue(types.Count == 1);
Assert.IsTrue(types[0].GetType == typeof(MyType2));

Scenario: I go through bunch of assemblies and as I go I register types but I want to make sure that I have only one implementation of a given type. I need to do this before I create the container. I could track that on my own but it would be nice if Autofac could help me a bit.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
Pawel Pabich
  • 2,404
  • 4
  • 22
  • 33
  • I have another reason for wanting this: Using RegisterAssemblyTypes I get a default 'background' of `InstancePerDependencyScope` resolutions. After this I want to upgrade some of them to `InstancePerLifetimeScope`. This works fine by re-registering them until such point as I resolve an enumerable of some interface (e.g. one that's implemented on more than one class). Removing the 'background' registration would allow this. – Josh Gallagher May 11 '14 at 07:31
  • 3
    For my particular issue I discovered `RegisterAssemblyTypes().Except()` and other fluent methods that can control the selection and treatment of assembly types being registered. – Josh Gallagher May 11 '14 at 07:46

2 Answers2

16

This cannot be done directly using the ContainerBuilder, unless you start over with a new one. Mind you, having first built a container you should be able to construct a new container filtering away unwanted types and reusing the registrations from the first container. Like this:

...
var container = builder.Build();

builder = new ContainerBuilder();
var components = container.ComponentRegistry.Registrations
                    .Where(cr => cr.Activator.LimitType != typeof(LifetimeScope))
                    .Where(cr => cr.Activator.LimitType != typeof(MyType));
foreach (var c in components)
{
    builder.RegisterComponent(c);
}

foreach (var source in container.ComponentRegistry.Sources)
{
    cb.RegisterSource(source);
}

container = builder.Build();

This is hardly very elegant but it works. Now, if you could elaborate on why you want to do this, perhaps there is a better way.

Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • Clever idea. You'd also need to copy the RegistrationSources property across, but this would work. – Nicholas Blumhardt Feb 24 '11 at 09:42
  • 1
    @Nicholas - there, added copying the sources. Also, not sure what implications it had, but I ended up with duplicates of the `LifetimeScope` component. So filtering out that one too. – Peter Lillevold Feb 24 '11 at 14:07
  • @Nicholas Blumhardt, could you please explain why do we need it? register/resolve functionality works without second foreach – monstr Aug 24 '17 at 11:08
  • 1
    Is there a bug in this? What is 'c' in the line foreach (var source in c.ComponentRegistry.Sources) – Damien Sawyer Jun 08 '18 at 20:17
  • @NicholasBlumhardt I ran across this question looking for a solution to an issue I'm facing with decorators (see: https://stackoverflow.com/questions/52611948/can-an-autofac-decorator-be-registered-to-override-existing-registrations). Replacing the registrations probably isn't the answer, but it's a case where it would come in handy to be able to do so. The better solution in my case would be if decorator registrations overrode existing registrations like other components. – Derek Greer Oct 02 '18 at 15:51
  • 1
    Late to the party; I just want to provide motivation. We are running tests on our API, which uses AutoFac for dependencies. We, however, would like to override the dependencies for some of our IO-dependent services. This is easy to do when you have a simple flat dependency, however, we have a composite that we want to remove. This is, for instance, more difficult. similarly, when utilizing decorators a similar issue arises. – Casper Bang Jul 04 '22 at 07:40
1

Peter L.'s probably got the most straightforward option.

To get around the problem altogether, can you modify the way you're discovering components to filter them in advance of registration? It does seem like there must be an approach that gets around this... It also might be a challenge further down the track to work out which components to keep vs. which to remove.

A more involved approach is to override IEnumerable support to filter out the the things you don't want. I.e. copy and modify this code to create a FilteredCollectionSource that excludes the components you don't want.

var elements = c.ComponentRegistry.RegistrationsFor(elementTypeService);

would become:

var elements = c.ComponentRegistry.RegistrationsFor(elementTypeService)
    .Where(reg => /* not a duplicate */);

If you add your FilteredCollectionSource to the builder using RegisterSource() it will should get used instead of the built-in one.

Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101