Как передать аргумент во время выполнения?
Мы мигрируем из StructureMap в Lamar, но я не смог найти "версию Lamar" для передачи аргументов во время выполнения.
У нас есть класс, который требует строковый аргумент (псевдокод):
public class MyRepository {
public MyRepository(string accountId) {}
}
... и завод
public class MyRepoFactory(Container container) {
public MyRepository GetRepositoryForAccount(string accountId) =>
container
// With() is not available in Lamar?
.With("accountId").EqualTo(accountId)
.GetInstance<IMyRepository>();
}
На самом деле существуют дополнительные зависимости.
Как можно сказать, Ламар GetInstance()
за IMyRepository
и использовать значение xy для аргумента конструктора с именем accountId
?
1 ответ
Я вижу два подхода с Ламаром.
Использование свойств
Пока Ламар не предлагает With()
Обходной путь может заключаться в том, чтобы сделать учетную запись свойством, заданным вами в методе фабрики, или чтобы фабрика просто получала все зависимости хранилища вручную из контейнера. В конце концов, это фабрика, поэтому ее тесная связь с типом, который она производит, кажется хорошей с точки зрения дизайна.
Использование контекстов
Более хорошим подходом может быть установка accountId в контексте и использование контекста в хранилище:
public class ExecutionContext
{
public Guid AccountId { get; set; } = Guid.NewGuid();
}
Репозиторий выглядит так
public class MyRepository
{
public ExecutionContext Context { get; }
public MyRepository(ExecutionContext context)
{
Context = context;
}
}
Сделать контекст инъекционным...
var container = new Container(_ =>
{
_.Injectable<ExecutionContext>();
});
а потом на вашем заводе...
public MyRepository GetRepositoryForAccount(string accountId) {
var nested = container.GetNestedContainer();
var context = new ExecutionContext{ AccountId = accountId };
nested.Inject(context);
return nested.GetInstance<IMyRepository>()
}
Документация: https://jasperfx.github.io/lamar/documentation/ioc/injecting-at-runtime/
Вы также можете подумать, действительно ли вам нужна фабрика в этом сценарии, если использование вложенного, инъецируемого контейнера напрямую может привести к более чистому дизайну.
Грубым, но простым решением может быть следующий код:
var type = container.Model.DefaultTypeFor(typeof(IMyRepository));
var constructor = type.GetConstructor(new[] { typeof(string) });
var instance = constructor.Invoke(new object[] { accountId });
return (IMyRepository)instance;