简体   繁体   中英

Resolve DbContext by Interface in EFCore 3

What's the correct way to register/resolve a DbContext by an Interface?


Context:

I have multiple web services with a different dbcontext each.

Since I need to write some common functionalities in a shared project, I wrote an interface which is implemented by each dbcontext, so I can have the set of shared functionalities "dbcontext-implementation-agnostic" just injecting the dbcontext interface.

In each project, each dbcontext is already used and injected by its implementation , but I would like to use just its interface in the common features project.

So, in each webservice I would have something like:

services.AddDbContext<IMyDbcontext, MyDbcontext>(options =>
{
    options.UseSqlServer(configuration.GetConnectionString("MyDbContext"));
});
services.AddTransient<ISharedService, SharedService>();

and in the shared project

public class SharedService : ISharedService
{
    public SharedService(IMydbcontext context)
    {
        [...]
    }

    [...]
}

having IMyDbcontext just like

public interface IMyDbcontext
{
    DbSet<SharedSettings> Settings { get; set; }

    int SaveChanges(bool acceptAllChangesOnSuccess);
    int SaveChanges();
    Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default);
    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}

and I require ISharedService within Startup.cs - Configure() with

app.ApplicationServices.GetService<ISharedService>();

I've been googling a lot and tried different approches but I couldn't find one which worked...

I've tried to use a forwarder, like this: (as suggested here )

services.AddDbContext<MyDbContext>();
services.AddScoped<IMyDbContext>(provider => provider.GetRequiredService<MyDbContext>());

But, while I've no issues resolving the concrete MyDbContext , I get this error whenever I try to resolve IMyDbContext

System.InvalidOperationException: 'Cannot resolve 'Blah.IMyService' from root provider because it requires scoped service 'Blah.IMydbcontext'.'

where IMyService is registered as transient and it's implementation constructor is

public MyService(IMydbcontext context)

I also tried to register the dbcontext like this

services.AddDbContext<IMyDbContext, MyDbContext>();

but then, when I try to resolve MyDbContext i get null , and I can't understand why

As pointed out by /u/AngularBeginner :

The IMyService requires a scoped IMyDbContext , but within your startups Configure() method you don't have a scope.

You can make your IDbContext transient (if that's acceptable to you).

Alternatively you can try to create a temporary scope using the CreateScope() method, then get your IMyService from that new scoped provider.

Source

So, I created a scope with IServiceScopeFactory and it did the trick

var scopeFactory = app.ApplicationServices.GetService<IServiceScopeFactory>();   
using var scope = scopeFactory.CreateScope();
var myService = scope.ServiceProvider.GetService<IMyService>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM