David Pavelka
David Pavelka

Reputation: 393

Singleton with DbContext - creating instance in Startup.cs

I am using ASP.net core. I have problem with implementing dbcontext into singleton.

I need my singleton IModuleRepository to be running right after start of the project. So I am creating new instance of this dependency in public void ConfigureServices(IServiceCollection services) in Startup.cs file.

This singleton is using another singleton, so I am using it like this:

services.AddDbContext<ModulesDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")).EnableSensitiveDataLogging());
...    
services.AddSingleton<IModuleRepository, ModuleRepository>();
services.AddSingleton<ICommunicationRepository>(new CommunicationRepository(services.BuildServiceProvider().GetService<IModuleRepository>()));

In ModuleRepository I am using DBcontext.

// Db context
    private readonly ModulesDbContext _modulesDbContext;

    public ModuleRepository(ModulesDbContext modulesDbContext)
    {
        _modulesDbContext = modulesDbContext;
    }

When I am calling _modulesDbContext.SomeModel.ToList(); I get error:

System.InvalidOperationException: An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point.

How to avoid this error when I need this singleton to run after the project is started?

Thank you for your help.

Upvotes: 3

Views: 2900

Answers (2)

David Pavelka
David Pavelka

Reputation: 393

I figured out this problem. This calling of the dependencies were right. The error is that in CommunicationRepository I've created 2 Task and both of them were using the same DbContext - so it was using it multiple times. I had to say task.Wait();

Full code in constructor of the CommunicationRepository after correction:

// Add pernament communication
        var task = new Task(AddPernamentCommunicationAll);
        task.Start();
        task.Wait();

        // Add modules
        var taskModules = new Task(AddModulesToList);
        taskModules.Start();

Thank you for your answers.

Upvotes: -1

juunas
juunas

Reputation: 58863

As @Ilya Chumakov commented, you could just tell the DI container to use your concrete class like so:

services.AddSingleton<ICommunicationRepository, CommunicationRepository>();

Then any class can depend on ICommunicationRepository and get the concrete repository, which gets the Db context.

Upvotes: 2

Related Questions