Как получить 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();
}