Сконфигурируйте 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.

Другие вопросы по тегам