Search code examples
c#inversion-of-controlautofac

Autofac : Questions about OnActivating and OnActivated


I have just started looking into using Autofac, and came across the Lifetime events OnActivating and OnActivated.

Now, I have read the Autofac documentation HERE

but it raises some questions on the difference between the two and their use.

Confusing points are:

  1. The above docs say OnActivated is raised "once a component is fully constructed". So, to me that implies for OnActivating the component is NOT fully constructed, otherwise why bother mentioning it just for this event. If that is to be believed then how come you can change properties, and call methods on the instance (via the IActivatingEventArgs.Instance property) if it is not ready?

  2. The docs say for OnActivating that it is "raised before the component is used". Does "used" mean before any Resolve method passes the component out to client code?

  3. Is the OnActivated event also raised BEFORE the component is "used"? The docs say nothing on this, but choose to mention it for the OnActivating event.

Would someone give a better account of when to use each event?


Solution

  • The OnActivated event is fired when the whole component graph is fully build whereas the OnActivating event is fired when the component is build.

    Let suppose we have this graph

    enter image description here

    class Parent
    {
        public Parent(Child1 child1, Child2 child2, Child3 child3) { }
    }
    class Child1
    { }
    class Child2
    {
        public Child2() { }
    }
    class Child3
    {
        public Child3(Child2 child2) { }
    }
    

    The event order will be :

    Parent.preparing
    Child1.preparing
    Child1.activating
    Child2.preparing
    Child2.activating
    Child3.preparing
    Child2.preparing
    Child2.activating
    Child3.activating
    Parent.activating
    Child1.activated
    Child2.activated
    Child2.activated
    Child3.activated
    Parent.activated
    Parent.release
    Child3.release
    Child2.release
    Child2.release
    Child1.release
    

    Here is the code to trace these events :

    public static class RegistrationExtensions
    {
        public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> 
            Trace<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registration)
        {
            return registration.OnPreparing(e => { Console.WriteLine($"{e.Component.Activator.LimitType.Name}.preparing"); })
                               .OnActivating(e => { Console.WriteLine($"{e.Component.Activator.LimitType.Name}.activating"); })
                               .OnActivated(e => { Console.WriteLine($"{e.Component.Activator.LimitType.Name}.activated"); })
                               .OnRelease(e => { Console.WriteLine($"{e.GetType().Name}.release"); }); ;
        }
    }
    

    The preparing event is fired before the instance is being created. You can provide new parameter for the activation process. The activating event let's you change the instance with the ReplaceInstance method. It is usefull if you want to mock or do any interception with the object. The activated event is really uncommon and you will almost never use it. The release event is fired when the associated lifetime scope is disposed

    In your case if you want to call a method to initialize your object you should use the activating event.