Как получить DbContext во вложенных методах, используя SimpleInjector

У меня есть сомнения, так как я новичок в зависимости и IoC.

У меня есть уровень домена (с бизнес-логикой) и уровень данных. Мы не реализуем репозитории, мы используем EF Core напрямую. Это проект библиотеки классов, мы используем его в веб-интерфейсе AspNetCore, WinForms и в другом фреймворке.

Идея состоит в том, чтобы использовать тот же контекст внутри области видимости.

Проблема в том, что я не могу получить тот же контекст при выполнении вложенного метода, я уверен, что это потому, что я не полностью понял концепцию, вы, ребята, можете мне помочь с этим?

Пример:

public class MyTest
{
    public void TestContainer()
    {
        var parentContext = MyContainer.Container.GetInstance<MyContext>();
        TestParentAndChildContext(parentContext); 
    }

    private void TestParentAndChildContext(MyContext parentContext)
    {
        var childContext = MyContainer.Container.GetInstance<MyContext>();
        Assert.AreEqual(parentContext, childContext);
    }
}

public class MyContainer
{
    public static Container Container
    {
        get { return container ?? (container = RegisterAndVerifyContainer()); }
    }

    private static Container RegisterAndVerifyContainer()
    {
        var container = new Container();
        container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
        container.Register<DbContext, MyContext>(Lifestyle.Scoped);

        container.Verify();

        return container;
    }
}

1 ответ

Решение

В Simple Injector вы регистрируете реализацию по ее абстракции. В вашем случае вы зарегистрировали MyContext своим DbContext базовый тип. С этого момента Простой Инжектор будет знать, что ему нужно будет построить MyContext в случае, если кто-то просит DbContext, Это вся цель

Программа для интерфейса, а не реализация

В вашем случае, однако, хотя вы регистрируете MyContext по его абстракции вы запрашиваете новый экземпляр MyContext напрямую, вместо того, чтобы запрашивать его через абстракцию. Это заставляет Simple Injector искать MyContext в своем списке зарегистрированных абстракций. Поскольку нет регистрации для MyContext (есть для DbContext хотя, но это совсем другой тип, что касается Simple Injector), Simple Injector попытается добавить отсутствующую регистрацию. Это успешно, потому что MyContext является конкретным и имеет один разрешаемый конструктор. По умолчанию Simple Injector разрешает незарегистрированные конкретные типы как Transient,

Так MyContext разрешается как переходный процесс при запросе напрямую. Вы можете решить эту проблему, изменив свой тест на следующее:

public void TestContainer()
{
    using (MyContainer.Container.BeginExecutionContextScope()) {
        var parentContext = MyContainer.Container.GetInstance<DbContext>();
        TestParentAndChildContext(parentContext); 
    }
}

private void TestParentAndChildContext(MyContext parentContext)
{
    var childContext = MyContainer.Container.GetInstance<DbContext>();
    Assert.AreEqual(parentContext, childContext);
}

Обратите внимание, что Simple Injector обычно выявляет подобные ошибки. Если вы зарегистрируетесь MyContext своим DbContext базовый тип, но вводить MyContext непосредственно в конструкторе типа, Simple Injector выдаст ошибку короткого замыкания при вызове Verify(),

Причина, по которой вас не предупредили об этом, заключается в том, что вы позвонили Verify() перед разрешением действий (как правило, вы не должны звонить GetInstance из вашего приложения; вместо этого вы должны построить все графы объектов заранее). Но когда ты позвонишь Verify (снова) после разрешения MyContext вы бы увидели исключение, появляющееся:

[TestMethod]
public void TestContainer()
{
    var container = MyContainer.Container.GetInstance<DbContext>();
    var parentContext = container.GetInstance<MyContext>();
    var childContext = container.GetInstance<MyContext>();

    // This call will fail
    container.Verify();
}
Другие вопросы по тегам