Добавление активированных событий для регистрации компонентов, которые были активированы автоматически - PullRequest
0 голосов
/ 26 сентября 2018

Я пытаюсь присоединить обработчик событий Activated к Components, который реализует определенный интерфейс.

Я хочу сделать это в одном месте глобально, и мне не нужно вызывать метод для каждогопостановка на учет.то есть OnActivation не подходит, так как это вызов для каждой регистрации.

Для этого у меня есть RegisterBuildCallback, который зацикливается на ComponentRegistry.Registrations, присоединяясь к событию Activated, где это необходимо.

Проблема, которую я обнаружил, заключается в том, что Components, помеченный как AutoActivate, активируется до запуска RegisterBuildCallback.Так что Activated не вызывается для AutoActivate Components, или, скорее, вызывается до того, как я прикрепил обработчик событий.

AutoActivate работает, как предполагалось, и как описано в документации:

Автоматически активируемый компонент - это компонент, который просто необходимо активировать один раз при сборке контейнера .

https://autofaccn.readthedocs.io/en/latest/lifetime/startup.html#auto-activated-components

Вот MCVE:

using System;
using System.Linq;

using Autofac;

namespace AutofacActivatedNotCalled
{
    public interface ISomething { }
    public interface IFoo { }
    public interface IBar { }
    public class Foo : IFoo, ISomething { }
    public class Bar : IBar, ISomething { }
    public class Baz { public Baz(IFoo foo) { } }

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();

            // Add callback which hooks up Activated event.
            builder
                .RegisterBuildCallback(builtContainer =>
                {
                    var iSomethingRegistrations = builtContainer
                        .ComponentRegistry
                        .Registrations
                        .Where(registration => IsISomething(registration.Activator.LimitType))
                        .ToList();

                    Console.WriteLine($"Found {iSomethingRegistrations.Count} ISomething Registrations");

                    foreach (var iSomethingRegistration in iSomethingRegistrations)
                    {
                        Console.WriteLine($"ISomething {iSomethingRegistration.Activator.LimitType.Name} Add Activated");

                        iSomethingRegistration.Activated += (sender, eventArgs) =>
                        {
                            Console.WriteLine($"ISomething {eventArgs.Instance.GetType().Name} Activated");
                        };
                    }
                });

            // Register services
            builder.RegisterType<Foo>().As<IFoo>().SingleInstance();

            builder
                .RegisterType<Bar>()
                .As<IBar>()
                .SingleInstance()
                .AutoActivate()
                .OnActivated(eventArgs => Console.WriteLine($"IBar Activated"));

            builder.RegisterType<Baz>();

            // Build container
            var container = builder.Build();

            // Resolve service
            var baz = container.Resolve<Baz>();

            Console.ReadLine();
        }

        private static bool IsISomething(Type type)
            => (type == typeof(ISomething))
            || type.GetInterfaces().Any(interfaceType => interfaceType == typeof(ISomething));
    }
}

Вот вывод:

    IBar Activated
    Found 2 ISomething Registrations
    ISomething Foo Add Activated
    ISomething Bar Add Activated
    ISomething Foo Activated

Как уже упоминалось, я стараюсь избегать использования OnActivated при регистрации Component.Он включен в пример, чтобы показать, что Activate запускается, но до запуска RegisterBuildCallback.

Есть ли способ обработать AutoActivated Components с моим подходом?

1 Ответ

0 голосов
/ 26 сентября 2018

AutoActivate активируются сразу после вызова метода Build.Вам даже не нужно событие Activated, чтобы поймать их.

Добавьте следующий код к RegisterBuildCallback -

var autoActivated = builtContainer
                                      .ComponentRegistry
                                      .Registrations
                                      .Where(registration => IsISomething(registration.Activator.LimitType) && registration.Services.Any(i => i.Description.Equals("AutoActivate")))
                                      .ToList();

                foreach (var iSomethingRegistration in autoActivated)
                {
                    Console.WriteLine($"Auto activated {string.Join("-", iSomethingRegistration.Services)} ");
                }
...