Skip to content
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

When using DbContextOptionsBuilder.UseModel with a singleton Instance, EF crashes when trying to initialize the model in multiple threads #25205

Closed
linusconcepcion opened this issue Jul 6, 2021 · 0 comments · Fixed by #25559
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@linusconcepcion
Copy link

Here is my OnConfiguring logic in my DbContext class:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
    {
        optionsBuilder
            .UseSqlServer("Server=DESKTOP-TEST,49172;Database=DbDirectory;User ID=xyz;password=xyz")
            .UseModel(EFCoreBug.Compiled.OrigamiDbContextModel.Instance);
    }
}

The IModel being generated is a static singleton that was generated by the dotnet ef dbcontext optimize command line tool.

I am running a console application that generates multiple threads, and each thread creates a new DbContext and fetches data from the db. That code looks like this:

static void Main(string[] args)
{
     // ADDED this line to fix:
     //using (var ctx = new OrigamiDbContext()) { var test = ctx.Accounts.FirstOrDefault(); };
     // END:

    var tasks = new List<System.Threading.Tasks.Task>();
    for (var i = 0; i < 20; i++)
    {
        tasks.Add(System.Threading.Tasks.Task.Factory.StartNew((threadIndex) =>
        {
            Console.WriteLine("Starting Thread: " + threadIndex);
            using (var ctx = new OrigamiDbContext())
            {
                var account = ctx.Accounts.FirstOrDefault();
                Console.WriteLine(threadIndex + ": " + account.Name);
            }

        }, i+1));
    }
    System.Threading.Tasks.Task.WaitAll(tasks.ToArray());

    Console.WriteLine("Done.");
    Console.ReadLine();
}

When I run this code, eventually, I get a crash with this call-stack:

Unhandled exception. System.AggregateException: One or more errors occurred. (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel) (The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel)
 ---> System.InvalidOperationException: The annotation 'Relational:ModelDependencies' cannot be added because an annotation with the same name already exists on the object EFCoreBug.Compiled.OrigamiDbContextModel
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.AddRuntimeAnnotation(String name, Annotation annotation) in Microsoft.EntityFrameworkCore.dll:token 0x60019ed+0x20
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.AddRuntimeAnnotation(String name, Object value) in Microsoft.EntityFrameworkCore.dll:token 0x60019ec+0x15
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.Microsoft.EntityFrameworkCore.Infrastructure.IAnnotatable.AddRuntimeAnnotation(String name, Object value) in Microsoft.EntityFrameworkCore.dll:token 0x60019fc+0x0
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelRuntimeInitializer.InitializeModel(IModel model, Boolean designTime, Boolean prevalidation) in Microsoft.EntityFrameworkCore.Relational.dll:token 0x6001431+0x3
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.<>c.<Initialize>b__4_0(ValueTuple`4 args) in Microsoft.EntityFrameworkCore.dll:token 0x6002cef+0x2d
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.<>c__30`2.<GetOrAddRuntimeAnnotationValue>b__30_0(String n, ValueTuple`3 t) in Microsoft.EntityFrameworkCore.dll:token 0x6002cc9+0x0
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd[TArg](TKey key, Func`3 valueFactory, TArg factoryArgument) in System.Collections.Concurrent.dll:token 0x60000d4+0x4f
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.GetOrAddRuntimeAnnotationValue[TValue,TArg](String name, Func`2 valueFactory, TArg factoryArgument) in Microsoft.EntityFrameworkCore.dll:token 0x60019f2+0x2e
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger) in Microsoft.EntityFrameworkCore.dll:token 0x6001b25+0x56
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime) in Microsoft.EntityFrameworkCore.dll:token 0x6001c35+0xb8
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() in Microsoft.EntityFrameworkCore.dll:token 0x6001c37+0xa
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) in Microsoft.EntityFrameworkCore.dll:token 0x6002cd9+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000094+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x23
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x66
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008f+0xe
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a5+0x57
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008d+0x39
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x3f
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x66
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008f+0xe
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a5+0x57
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008d+0x39
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x3f
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x66
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008f+0xe
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a5+0x57
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008d+0x39
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x3f
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x66
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008f+0xe
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a5+0x57
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600008d+0x39
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000a6+0x3f
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x66
...

The call stack is too large to post here, so I cut it off for brevity, however, I do believe that the above exception is easily reproducable in any db.

I'm happy to zip up and attach a small project, however, I'm not sure how to get a Db included with this bug ticket.

I believe the issue is that the .UseModel(dbModel) call that is happening across the threads will all run initialization code against the same instance of the IModel, and that, at this point is NOT thread safe. If for example, you uncomment the first commented line in the sample code above, then the code works ok because the first line causes the singleton model to be initialized fully without other threads trying to do the same.

Include provider and version information

EF Core version: 6.0.0-preview.7.21355.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.0.0 preview 1.1

@AndriySvyryd AndriySvyryd self-assigned this Jul 6, 2021
@AndriySvyryd AndriySvyryd added this to the 6.0.0 milestone Jul 6, 2021
@AndriySvyryd AndriySvyryd added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug and removed type-bug labels Aug 17, 2021
@AndriySvyryd AndriySvyryd removed their assignment Aug 17, 2021
@AndriySvyryd AndriySvyryd modified the milestones: 6.0.0, 6.0.0-rc2 Aug 18, 2021
@ajcvickers ajcvickers modified the milestones: 6.0.0-rc2, 6.0.0 Nov 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants