Остановить модуль Autofac, регистрирующий уже зарегистрированные компоненты - PullRequest
6 голосов
/ 06 декабря 2011

У меня есть модуль Autofac, который имеет следующую (урезанную) логику в переопределении нагрузки:

protected override void Load(ContainerBuilder builder)
    {
        foreach (var componentType in allTypesInAllAvailableAssemblies) // Set elsewhere
        {
            var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>)));
            if (handlerInterfaces.Any())
                builder.RegisterType(componentType).As(handlerInterfaces);
        }
    }

Это ищет любой класс, который объявляет себя обработчиком сообщения и регистрирует его для всех IMessageHandlerинтерфейсы, которые он реализует.

Что я хочу сделать, это не зарегистрировать компонент, если он уже зарегистрирован.В качестве бонуса было бы идеально, если бы я мог обновить существующую регистрацию для разрешения интерфейса (ов) обработчика сообщений, если это еще не сделано.

В качестве аргумента можно предположить, что этот кодбудет запускаться после все другие типы будут зарегистрированы (включая возможные кандидаты обработчика сообщений)

Я использовал переопределение AttachToComponentRegistration для манипуляций с регистрацией в прошлом, но это не похоже наэто полезно в этом сценарии.

Возможно ли это, или я должен переосмыслить свой дизайн и заставить плагины явно объявить свои обработчики?

Ответы [ 2 ]

8 голосов
/ 06 декабря 2011
builder.RegisterType(componentType)
    .As(handlerInterfaces)
    .PreserveExistingDefaults();

Будет работать.

1 голос
/ 06 декабря 2011

К сожалению, не существует элегантного способа сделать то, что вы хотите.Контейнер Autofac и его конструктор являются «черными ящиками», которые не позволяют вам хорошо рассмотреть то, что у вас уже есть.

При двойной регистрации компонента нет вреда, ЕСЛИ БЕЗ ваших регистраций не выполнено-зависимый (BAD, BAD, BAD).Повторная регистрация просто перезапишет старую регистрацию новой.

Я серьезно подвергаю сомнению этот код, поскольку он полностью зависит от того, как инициализируется allTypesInAllAvailableAssemblies.Если это действительно каждый тип в вашей системе, то это дерьмовая стрельба относительно того, что решит, скажем, IDisposable.Если у вас есть несколько различных реализаций, скажем, IConfigurator, вы будете иметь ограниченный контроль над тем, какая из них в итоге будет зарегистрирована, независимо от того, проверяете ли вы то, что уже зарегистрировано, или просто перезаписываете регистрацию;это полностью зависит от того, какой класс окажется первым (или последним) в списке.

Единственное, что я мог подумать, это использовать небольшой Linq, чтобы убедиться, что список типов, которые вы регистрируете, уникален:

protected override void Load(ContainerBuilder builder)
{
    foreach (var componentType in allTypesInAllAvailableAssemblies.OfType<Type>().Distinct()) // Set elsewhere
    {
        var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>)));
        if (handlerInterfaces.Any())
            builder.RegisterType(componentType).As(handlerInterfaces);
    }
}

Это гарантирует, что каждый экземпляр componentType никогда не был замечен сборщиком ранее, в рамках этого цикла foreach.Это означает, что, учитывая, что это единственный модуль, используемый для создания контейнеров, и каждый контейнер создается только один раз и никогда не обновляется, каждый компонент в системе будет зарегистрирован в любом данном контейнере ровно один раз.Общие интерфейсы, такие как IDisposable, IEnumerable, IComparable, IComparer и т. Д., Будут бесполезны для решения;они будут преобразованы в экземпляр последнего класса, у которого был этот интерфейс.

Если вам нужно убедиться, что интерфейс никогда не был зарегистрирован или этот код также работает при использовании ContainerBuilder для Update () исуществующий контейнер, просто остановите то, что вы делаете, потому что вы собираетесь создать безнадежный беспорядок, который вы никогда не сможете поддерживать должным образом.

...