Разрешить DbContext по интерфейсу в EFCore 3

Как правильно зарегистрировать/разрешить DbContext с помощью интерфейса?


Контекст:

У меня есть несколько веб-сервисов с разными dbcontext.

Поскольку мне нужно написать некоторые общие функции в общем проекте, я написал интерфейс, который реализуется каждым dbcontext, поэтому у меня может быть набор общих функций «dbcontext-implementation-agnostic», просто внедряющий интерфейс dbcontext.

В каждом проекте каждый dbcontext уже используется и внедряется его реализацией, но я хотел бы использовать только его интерфейс в проекте общих функций.

Итак, в каждом веб-сервисе у меня было бы что-то вроде:

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

и в общем проекте

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

    [...]
}

имея IMyDbcontext так же, как

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);
}

и мне требуется ISharedService в Startup.cs - Configure() с

app.ApplicationServices.GetService<ISharedService>();

Я много гуглил и пробовал разные подходы, но я не мог найти тот, который работал...

Я пытался использовать пересылку, например: (как предложено здесь)

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

Но, хотя у меня нет проблем с решением конкретной MyDbContext, я получаю эту ошибку всякий раз, когда пытаюсь решить IMyDbContext

System.InvalidOperationException: «Не удается разрешить «Blah.IMyService» от корневого провайдера, поскольку для этого требуется служба с ограниченной областью действия «Blah.IMydbcontext».

где IMyService зарегистрирован как переходный, а его конструктор реализации

public MyService(IMydbcontext context)

Я также пытался зарегистрировать dbcontext следующим образом

services.AddDbContext<IMyDbContext, MyDbContext>();

но затем, когда я пытаюсь решить MyDbContext, я получаю null, и я не могу понять, почему


person Doc    schedule 06.12.2019    source источник
comment
можете ли вы показать более подробный пример текущего запуска, а также соответствующие классы. Неясно, нужен ли вам интерфейс или реализация.   -  person Nkosi    schedule 06.12.2019
comment
Что ты пытаешься сделать? Если вы хотите разрешить как MyDbContext, так и IMyDbContext, вам придется зарегистрировать оба типа. AddDbContext<IMyDbContext, MyDbContext> регистрирует только IMyDbContext с реализацией, предоставленной MyDbContext. Достаточно просто зарегистрировать MyDbContext — любой код, который ожидает MyDbContext, получит его и никогда не узнает, откуда взялись данные, например, из базы данных или словаря.   -  person Panagiotis Kanavos    schedule 06.12.2019
comment
я добавил больше контекста   -  person Doc    schedule 06.12.2019


Ответы (1)


Как указал /u/AngularBeginner:

Для IMyService требуется IMyDbContext с областью действия, но в методе Configure() вашего запуска у вас нет области.

Вы можете сделать свой IDbContext временным (если это приемлемо для вас).

В качестве альтернативы вы можете попытаться создать временную область с помощью метода CreateScope(), а затем получить свой IMyService от этого поставщика с новой областью действия.

Источник

Итак, я создал область с помощью IServiceScopeFactory, и это помогло.

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