New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConditionalRegistration not supported when AllowOverridingRegistrations message confusing #384

Closed
andycmaj opened this Issue Feb 22, 2017 · 2 comments

Comments

2 participants
@andycmaj

andycmaj commented Feb 22, 2017

I'm seeing this error message when trying to register services:

Unhandled Exception: System.NotSupportedException: The making of conditional registrations is not supported when AllowOverridingRegistrations is set, because it is impossible for the container to detect whether the registration should replace a different registration or not.

   at SimpleInjector.Internals.GenericRegistrationEntry.ThrowWhenConditionalIsRegisteredInOverridingMode(OpenGenericToInstanceProducerProvider provider)
   at SimpleInjector.Internals.GenericRegistrationEntry.AddGeneric(Type serviceType, Type implementationType, Lifestyle lifestyle, Predicate`1 predicate)
   at TheChunnel.Activities.Marketing.Webhooks.BaseWebhooksActivityModule`2.ConfigureDependencies(Container container) in /Workspaces/appature/git/TheChunnel/activities/TheChunnel.Activities.Marketing/Webhooks/BaseWebhooksActivityModule.cs:line 33

I was very confused by this until i dug into SI src code, because i don't have any conditional registrations at all in this container.

Unless i'm misunderstanding

, it looks like this validation considers Open Generic registrations conditional.

private void ThrowWhenConditionalIsRegisteredInOverridingMode(
    OpenGenericToInstanceProducerProvider provider)
{
    if (!provider.AppliesToAllClosedServiceTypes && this.container.Options.AllowOverridingRegistrations)
    {
        // We allow the registration in case it doesn't have a predicate (meaning that the type is
        // solely conditional by its generic type constraints) while it is the first registration.
        // In that case there is no ambiguity, since there's nothing to replace (fixes #116).
        if (this.providers.Any() || provider.Predicate != null)
        {
            throw new NotSupportedException(
                StringResources.MakingConditionalRegistrationsInOverridingModeIsNotSupported());
        }
    }
}

basically, the messaging here is very confusing, since it mentions nothing about open generics.

@dotnetjunkie

This comment has been minimized.

Collaborator

dotnetjunkie commented Feb 22, 2017

Very good point. The message should state that your registered type contains a generic type constraint and is therefore considered conditional.

But in case this registration is the only registration, it might even be possible to still safely replace it. I will do some research.

Thanks for taking the time to dive into the source code and report this.

@andycmaj

This comment has been minimized.

andycmaj commented Feb 22, 2017

hey actually i have another twist on this :)

so i was doubly confused because i noticed in my code, another open generic registration that was NOT causing this exception, and WAS repeated multiple times (due to plugin model) in override-allowed mode.

here's the registration that was allowed to override without error:

container.Register(typeof(IS3Store<>), typeof(S3Store<>));

and here are the corresponding interface and concrete types:

public interface IS3Store<T> where T : class { }
public class S3Store<T> : IS3Store<T>  where T : class { }

now... HERE is the registration that caused the failure:

container.Register(typeof(IRepository<>), typeof(S3Repository<>));

... and the corresponding types:

public interface IRepository<TEntity> { }
public class S3Repository<TEntity> where TEntity : class  { }

SO, it turns out that i had a generic constraint mismatch on one of my interface/implementation pairs. When that was fixed (by adding missing where TEntity : class constraint to the IRepository<> interface), the error message goes away 😄

But in case this registration is the only registration, it might even be possible to still safely replace it. I will do some research.

So yeah, that makes sense... it seems you already DO allow replacement with the SAME registration, IF the implementation type exactly matches the service type (which mine didn't).

Haven't dug in deep enough to understand why that matters, but i'm guessing something to do with your providers/genericregistrationentry logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment