0

I try to setup the DI for a new ASP.NET Core site and I have this code:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    // Get the configuration from the app settings.
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .Build();

    // Get app settings to configure things accordingly.
    var appSettings = Configuration.GetSection("AppSettings");
    var settings = new AppSettings();
    appSettings.Bind(settings);

    services
        .AddOptions()
        .Configure<AppSettings>(appSettings)
        .AddSingleton<IConfigurationRoot>(config)
        .AddDbContext<MyDbContext>(builder =>
        {
            builder.UseSqlServer(config.GetConnectionString("myConn"));
        }, ServiceLifetime.Transient, ServiceLifetime.Transient);

    services.AddSingleton<ILoadTestCleanUpServiceRepository, LoadTestCleanUpServiceRepository>();
        ...

Now, the LoadTestCleanUpServiceRepository depends on the MyDbContext:

public class LoadTestCleanUpServiceRepository : ILoadTestCleanUpServiceRepository
{
    private readonly MyDbContext _dbContext;

    public LoadTestCleanUpServiceRepository(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    ...

..and the DB Context is this:

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> ctxOptions) : base(ctxOptions)
    {
    }
}

When I run the application, I get this error:

InvalidOperationException: Unable to resolve service for type 'MyCode.Infrastructure.Common.MyDbContext' while attempting to activate 'MyCode.Infrastructure.LoadTestCleanUpService.LoadTestCleanUpServiceRepository'.

I have tried changing the ServiceLifetime options and adding this extra code:

services.AddTransient<MyDbContext>(sp => new MyDbContext(config));

...but nothing seems to help and I cannot understand why this doesn't work. It does try to construct the repository, but why can't it construct the DB Context too? It doesn't even reach the point where I call UseSqlServer()! Any ideas?

UPDATE 1:

Hmm... I now see this. Most likely it is related:

enter image description here

UPDATE 2:

I have now :

  • Replaced EF 6 with Microsoft.EntityFrameworkCore.SqlServer
  • Upgraded to netcoreapp2.2 target framework to solve some conflicting assembly versions.
  • Made the repository scoped.

But I still get the same error.

8
  • Why MyDbContext class has AcDbContext for constructor? Is this code compile ? Commented Mar 27, 2019 at 9:05
  • @Dimitar Sorry. I've fixed that now. I "change" some parts of the code names to avoid leaking my project information. It is not any top secret stuff, but I try to make the code as "common" as possible. Commented Mar 27, 2019 at 9:07
  • I had a similar problem, and yes EF version mismatch is the only explanation for this Commented Mar 27, 2019 at 9:19
  • You cannot use a scoped database context within a singleton service. Trying to make the database context transient will also not fix that. Consider making your repository scoped itself instead. Commented Mar 27, 2019 at 9:32
  • 1
    Be aware that your MyDbContext is held captive as a Captive Dependency inside LoadTestCleanUpServiceRepository. Commented Mar 27, 2019 at 11:38

1 Answer 1

3

I see you have registered LoadTestCleanUpServiceRepository as Singleton while MyDbContext as Transient and then you are trying to resolve MyDbContext from LoadTestCleanUpServiceRepository. That's the problem. According to ASP.NET Core Service lifetimes documentation:

It's dangerous to resolve a scoped service/transient service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.

Solution is: register LoadTestCleanUpServiceRepository and MyDbContext as follows:

services.AddDbContext<MyDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("YourConnectionStringName")));

services.AddScoped<ILoadTestCleanUpServiceRepository, LoadTestCleanUpServiceRepository>();

Now problem should go away.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. After many changes, it worked. One thing that was really wrong was that I had defined two different DB contexts (accident after trying to move a single DB context) and that messed things up.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.