Сконфигурируйте autofac, чтобы игнорировать конструкторы, помеченные как устаревшие
Можно ли легко настроить автозапуск, чтобы он разрешался только с использованием устаревших конструкторов?
например, для класса с вспомогательным конструктором для кода без DI,
public class Example {
public Example(MyService service) {
// ...
}
[Obsolete]
public Example() {
service = GetFromServiceLocator<MyService>();
// ...
}
}
// ....
var builder = new ContainerBuilder();
builder.RegisterType<Example>();
// no MyService defined.
var container = builder.Build();
// this should throw an exception
var example = container.Resolve<Example>();
запросить у autoofac Пример, если мы не зарегистрировали MyService, произойдет сбой.
2 ответа
Я не верю, что есть оригинальный способ настроить Autofac на игнорирование Obsolete
Конструкторы. Однако, Autofac настолько хорош, что всегда есть способ сделать это:) Вот два варианта:
Вариант 1. Скажите Autofac, какой конструктор использовать
Сделайте это, используя UsingConstructor
метод продления регистрации.
builder.RegisterType<Example>().UsingConstructor(typeof(MyService));
Вариант 2. Предоставить кастом IConstructorFinder
в FindConstructorsWith
У Autofac есть метод расширения регистрации, называемый FindConstructorsWith
, Вы можете передать обычай IConstructorFinder
к одной из двух перегрузок. Вы могли бы написать простой IConstructorFinder
называется NonObsoleteConstructorFinder
он будет возвращать только конструкторы без атрибута устаревшего.
Я написал этот класс и добавил рабочую версию вашего образца. Вы можете просмотреть полный код и использовать его в качестве вдохновения. ИМО вариант это более элегантный вариант. Я добавил его в свой проект AutofacAnswers на GitHub.
Примечание. Другая перегрузка принимает BindingFlags. Я не думаю, что вы можете указать требования к атрибутам, используя BindingFlags
, Тем не менее, вы можете проверить это.
Это продолжение ответа бентайлорука. Я попробовал его вариант 2, но он не сработал. Вскоре я заметил, что это потому, что я использую перехватчики AutoFac. AutoFac передает тип прокси-класса в конструктор поиска, но эти конструкторы не имеют атрибутов, определенных для конструкторов в базовом классе.
Чтобы сделать эту работу, мой код сравнивает сигнатуры конструктора обоих классов, чтобы найти "правильный" конструктор, и проверяет, присутствует ли атрибут.
public class NonObsoleteConstructorFinder : IConstructorFinder
{
private readonly DefaultConstructorFinder _defaultConstructorFinder = new DefaultConstructorFinder();
public ConstructorInfo[] FindConstructors(Type targetType)
{
// Find all constructors using the default finder
IEnumerable<ConstructorInfo> constructors = _defaultConstructorFinder.FindConstructors(targetType);
// If this is a proxy, use the base type
if (targetType.Implements<IProxyTargetAccessor>())
{
// It's a proxy. Check for attributes in base class.
Type underlyingType = targetType.BaseType;
List<ConstructorInfo> constructorList = new List<ConstructorInfo>();
// Find matching base class constructors
foreach (ConstructorInfo proxyConstructor in constructors)
{
Type[] parameterTypes = proxyConstructor.GetParameters()
.Select(pi => pi.ParameterType)
.Skip(1) // Ignore first parameter
.ToArray();
ConstructorInfo underlyingConstructor = underlyingType.GetConstructor(parameterTypes);
if (underlyingConstructor != null &&
!underlyingConstructor.HasAttribute<ObsoleteAttribute>())
{
constructorList.Add(proxyConstructor);
}
}
constructors = constructorList;
}
else
{
// It's not a proxy. Check for the attribute directly.
constructors = constructors.Where(c => !c.HasAttribute<ObsoleteAttribute>());
}
return constructors.ToArray();
}
}
Примечание 1: Skip(1)
требуется, потому что первый аргумент конструктора прокси имеет тип IInterceptor[]
, Это используется AutoFac для прохождения перехватчиков.
Заметка 2: targetType.Implements<IProxyTargetAccessor>()
а также underlyingConstructor.HasAttribute<ObsoleteAttribute>()
являются методами расширения, предоставляемыми библиотекой Fasterflect.