Stop Autofac module by registering already registered components

I have an Autofac module that has the following (trimmed) logic in load redefinition:

protected override void Load(ContainerBuilder builder) { foreach (var componentType in allTypesInAllAvailableAssemblies) // Set elsewhere { var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); if (handlerInterfaces.Any()) builder.RegisterType(componentType).As(handlerInterfaces); } } 

This is a search for any class that declares itself a message handler and registers it with all the IMessageHandler interfaces that it implements.

What I want to do is not to register the component if it is already registered. As a bonus, it would be ideal if I could update an existing registration to allow it using the message handler interface (s) if it was not already.

For the argument, we can assume that this code will be run after registration of all other types (including possible candidates for message handlers)

I used the AttachToComponentRegistration override to manipulate registration in the past, but in this case it doesn't look like a useful one.

Is this possible, or should I review my design and strength plugins to explicitly declare their handlers?

+6
source share
2 answers
 builder.RegisterType(componentType) .As(handlerInterfaces) .PreserveExistingDefaults(); 

It will work if you do not start resolving handler lists.

+7
source

Unfortunately, there is no elegant way to do what you want. The Autofac container and its creator are black boxes that prevent you from looking at what you already have.

There is no harm when registering a component twice IF your registrations are independent of the order (BAD, BAD, BAD). Registering a second time will simply overwrite the old registration with the new one.

I seriously doubt this code, since it completely depends on how allTypesInAllAvailableAssemblies is initialized. If this is really every type in your system, then this shit shoots at something that will decide how, say, IDisposable. If you have several different implementations of, say, IConfigurator, you will have limited control over which one is registered, regardless of whether you check what is already registered or just overwrite the registration; it depends entirely on which class ends first (or last) in the list.

The only thing I could think of was to use a little Linq to make sure that the list of types you are registering is unique:

 protected override void Load(ContainerBuilder builder) { foreach (var componentType in allTypesInAllAvailableAssemblies.OfType<Type>().Distinct()) // Set elsewhere { var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); if (handlerInterfaces.Any()) builder.RegisterType(componentType).As(handlerInterfaces); } } 

This ensures that every instance of componentType has never been seen by a developer before, as part of this foreach loop. This means that, given that this is the only module used to assemble containers, and each container is created only once and never updated, each component in the system will be registered in any given container exactly once. Common interfaces, such as IDisposable, IEnumerable, IComparable, IComparer, etc., will be useless for a solution; they will allow an instance of the last class having this interface.

If you need to verify that the interface has never been registered or that this code also works when using ContainerBuilder to update () an existing container, just stop what you are doing because you are going to create a hopeless mess you can never maintain properly.

+1
source

Source: https://habr.com/ru/post/903148/


All Articles