Autofac: 4.9.3 Issue with Entity Framework Core DI registrations

Created on 23 Jul 2019  路  7Comments  路  Source: autofac/Autofac

TestApp-SingleDb.zip
_Originally posted by @danjohnso in https://github.com/autofac/Autofac/issues/972#issuecomment-514228006_

Moving from old issue. Repo is attached. When using the .AddEntityFrameworkSqlServer() extension for EF Core (need internal service provider for multitenant scenario), an InvalidOperation exception is thrown trying to resolve pieces for EF Core to operate. This issue does not occur in 4.9.2 and does not occur using the OOB IServiceProvider. If I do not use the internal service provider and avoid calling .AddEntityFrameworkSqlServer(), the issue goes away.

Not sure if this is an issue related to the change where I made my original comment or if this is an issue for the EF Core team to look at because of a poorly made registration. I figured I would start here since I can't reproduce with the OOB IServiceProvider.

Most helpful comment

Changes in the pull request no longer cause an exception in the reproduction project supplied, as well as passing the new test.

All 7 comments

I can confirm this issue! I ran into the same after updating from 4.9.2 to 4.9.3!

I can confirm this issue when upgrading from 4.9.2 to 4.9.3

The comment has the exception as:

Autofac.Core.DependencyResolutionException: An exception was thrown while activating 位:Microsoft.EntityFrameworkCore.Internal.DbContextDependencies -> Microsoft.EntityFrameworkCore.Internal.DbContextDependencies. ---> System.InvalidOperationException: This operation is only valid on generic types.
   at Type RuntimeType.GetGenericTypeDefinition()
   at bool Autofac.Util.TypeExtensions.ParameterCompatibleWithTypeConstraint(Type parameter, Type constraint) in C:\projects\autofac\src\Autofac\Util\TypeExtensions.cs:line 193
   at bool Autofac.Util.TypeExtensions.IsCompatibleWithGenericParameterConstraints(Type genericTypeDefinition, Type[] parameters)+(Type constraint) => { } in C:\projects\autofac\src\Autofac\Util\TypeExtensions.cs:line 83
   at bool System.Linq.Enumerable.Any<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
   at bool Autofac.Util.TypeExtensions.IsCompatibleWithGenericParameterConstraints(Type genericTypeDefinition, Type[] parameters) in C:\projects\autofac\src\Autofac\Util\TypeExtensions.cs:line 81
   at bool Autofac.Features.OpenGenerics.OpenGenericServiceBinder.TryBindServiceType(Service service, IEnumerable<Service> configuredOpenGenericServices, Type openGenericImplementationType, out Type constructedImplementationType, out Service[] constructedServices) in C:\projects\autofac\src\Autofac\Features\OpenGenerics\OpenGenericServiceBinder.cs:line 57
   at IEnumerable<IComponentRegistration> Autofac.Features.OpenGenerics.OpenGenericRegistrationSource.RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)+MoveNext()
   at ServiceRegistrationInfo Autofac.Core.Registration.ComponentRegistry.GetInitializedServiceInfo(Service service) in C:\projects\autofac\src\Autofac\Core\Registration\ComponentRegistry.cs:line 360
...

I do see this show up on the developer error page on _the first_ request. On every subsequent request, the exception appears different (and this one is logged to the console during the first request, too):

An unhandled exception was thrown by the application.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating 位:Microsoft.EntityFrameworkCore.Infrastructure.IResettableService[] -> 位:Microsoft.EntityFrameworkCore.Infrastructure.IResettableService -> Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager -> Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManagerDependencies. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManagerDependencies' can be invoked with the available services and parameters:
Cannot resolve parameter 'Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+Update] updateLogger' of constructor 'Void .ctor(Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IInternalEntityEntryFactory, Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IInternalEntityEntrySubscriber, Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IInternalEntityEntryNotifier, Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IValueGenerationManager, Microsoft.EntityFrameworkCore.Metadata.IModel, Microsoft.EntityFrameworkCore.Storage.IDatabase, Microsoft.EntityFrameworkCore.Internal.IConcurrencyDetector, Microsoft.EntityFrameworkCore.Internal.ICurrentDbContext, Microsoft.EntityFrameworkCore.Internal.IEntityFinderSource, Microsoft.EntityFrameworkCore.Internal.IDbSetSource, Microsoft.EntityFrameworkCore.Metadata.Internal.IEntityMaterializerSource, Microsoft.EntityFrameworkCore.Diagnostics.ILoggingOptions, Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+Update], Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+ChangeTracking])'.
   at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 160
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 120
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 117
   --- End of inner exception stack trace ---
...

Note to get the attached reproduction working, modifications need to be made:

  • Add a reference from the TestApp project to the Autofac.Multitenant package
  • In Startup change the logging so it goes to the console rather than to a local Seq instance.

I may not _personally_ have time to dive into this, however we have a lot of great new @autofac/contributors on board who may be able to help out here.

Okay, I've got a replicating unit test for this, it doesn't seem to be specific to EF, it looks like it might be related to self-referencing generics.

The logging categories in EFCore do this, which is why we see the problem.

So with the following types:

public interface IBaseGeneric<TDerived>
    where TDerived : BaseGenericImplementation<TDerived>, new()
{
}

public class SelfReferenceConsumer<TSource> : IBaseGeneric<TSource>
    where TSource : BaseGenericImplementation<TSource>, new()
{
}

public abstract class BaseGenericImplementation<TDerived>
{
}

public class DerivedSelfReferencing : BaseGenericImplementation<DerivedSelfReferencing>
{
}

This test fails with the same exception:

[Fact]
public void TestSelfReferentialGeneric()
{
    var cb = new ContainerBuilder();
    cb.RegisterGeneric(typeof(SelfReferenceConsumer<>)).As(typeof(IBaseGeneric<>));
    var container = cb.Build();

    container.Resolve<IBaseGeneric<DerivedSelfReferencing>>();
}

image

Now I've got a test for it I'll look at getting a fix together.

Changes in the pull request no longer cause an exception in the reproduction project supplied, as well as passing the new test.

Fix available in v4.9.4 on NuGet

Was this page helpful?
0 / 5 - 0 ratings