Именованный экземпляр Autofac - определите экземпляр по умолчанию, если не найден
Я использую Autofac для регистрации именованных экземпляров. Я должен переводить транзакции XML в объекты.
Во-первых, у меня есть перечисление.
public enum TransactionType
{
Unknown = 0,
[XmlNode("MyNodeA")]
TypeA = 1,
[XmlNode("MyNodeA")]
TypeB = 2
}
У меня есть метод, который создает IDictionary<string, TransactionType>
с использованием XmlNode
атрибут на перечислении.
Вот мой картограф
var mappings = TransactionTypeHelper.GetDictionary();
foreach (var mapping in mappings)
{
builder.Register(ctx => {
return mapping.Key;
})
.Named<TransactionType>(mapping.Value)
.InstancePerLifetimeScope();
}
Тогда у меня есть TransactionTypeFactory
для получения TransactionType
на основе узла XML.
public TransactionType GetTransactionType(string rootNode)
{
return _container.Resolve<TransactionType>(rootNode?.ToLower());
}
Моя проблема в том, что я хочу пройти через любые неизвестные узлы xml как неизвестные транзакции, чтобы я мог обрабатывать новые транзакции без внесения каких-либо изменений в код. Проблема в том, что _container.Resolve
выдает ошибку, если переданный узел не был зарегистрирован.
Я хочу, чтобы autofac возвращал enum по умолчанию, если именованный экземпляр не найден, вместо того, чтобы выдавать ошибку. Самое смешное, что у меня есть модульные тесты, в которых этот контейнер проверяется, и все они проходят, но Autofac специально взрывается при этом вызове.
0 ответов
Я знаю, что этот вопрос довольно старый, но я хотел бы поделиться решением, которое я узнал тем временем, в надежде, что он поможет кому-то с той же проблемой.
С помощью autofac вы можете зарегистрировать функцию, которая может разрешать с помощью логики.
Сначала вы должны зарегистрировать каждый именованный экземпляр. В вопросе я делал это с помощью помощника и перебирал коллекцию, но суть в том, чтобы сопоставить каждое значение перечисления с экземпляром.
builder.Register<TransactionAClass>(ctx =>
{
//get any instances required by ConcreteClass from the ctx here and pass into the constructor
return new TransactionAClass();
})
.Named<Interfaces.ITransactionInterface>($"{TransactionType.TypeA:f}")
.InstancePerLifetimeScope();
После того, как у вас будут все регистрации для известных значений, мы зарегистрируем функцию преобразователя.
builder.Register<Func<TransactionType, Interfaces.ITransactionInterface>>(ctx =>
{
//you must resolve the context this way before being able to resolve other types
var context = ctx.Resolve<IComponentContext>();
//get the registered named instance
return (type) =>
{
var concrete = context.ResolveNamed<Interfaces.ITransactionInterface>($"{type:f}");
if (concrete == null)
{
//return a default class or throw an exception if a valid registration is not found
return new TransactionAClass();
}
return concrete;
}
});
Затем вы можете использовать резолвер следующим образом
public class MyClass
{
private readonly ITransactionInterface transaction;
public MyClass(Func<TransactionType, Interfaces.ITransactionInterface> transactionResolver)
{
transaction = transactionResolver.Invoke(TransactionType.TypeA);
}
}