Search code examples
dependency-injectioninversion-of-controlautofac

What is the proper usage of InstancePerOwned in autofac dependency injection


I wanted to know what is the proper usage of InstancePerOwned<TService>() in Autofac. How can I use that when resolving dependencies?


Solution

  • Consider following code

    public interface IAnotherService
    {
        int Id { get; set; }
        string Lable { get; set; }
    }
    
    public class AnotherService : IAnotherService,IDisposable
    {
        public int Id { get; set; }
        public string Lable { get; set; }
    
    
        public AnotherService(/* loads of dependent components*/)
        {
    
        }
    
        public override string ToString()
        {
            return string.Format("My Id is:{0} and my lable is {1}", Id, Lable);
        }
    
        public void Dispose()
        {
            // Another Service is Disposing ;
        }
    }
    
    public interface IMyService
    {
        void DoSomething();
    }
    
    // MyService class depends on IAnotherService
    // MyService class is a huge and long-lived class where we have just ommited lots of other implementations
    public class MyService : IMyService
    {
        private readonly IAnotherService _anotherService;
    
        public MyService(IAnotherService anotherService)
        {
            _anotherService = anotherService;
        }
    
        public Void DoSomething()
        {
            Console.WriteLine(_anotherService.ToString());
        }
    
        //
        //
        //
        // The rest of the class
        //
        //
        //
        //
    }
    

    In above code MyService class depends on IAnotherService. So somehow in your dependency registration you would say

     builder.RegisterType<AnotherService>().As<IAnotherService>().InstancePerDependency();
    


    This makes sure anytime an instance of MyService is instantiated or resolved using Autofac, one instance of AnotherService will be resolved beforehand within the lifetimescope where MyService is being instantiated.

    While MyService is alive, in other word, it's parrent lifetimescope is alive, _anotherService needs to be alive whether or not it's being used in the rest of the code of MyService.

    Owned Instance

    Note that an Owned instance of a service is and object instantiated from a just-newly-created lifetimescope.

     Owned<IAnotherService> _anotherService ;
    


    The good point about this object (_anotherService ) is that before its instantiation

    1. a new lifetimescope will be initialized
    2. an instance of AnotherService is instantiated within newly created lifetimescope in step1

    3. new AnotherService instance and its container lifetimescope will be bound and form an instance of Owned and injected to MyService class.

    Anytime in the lifetime of MyService where you no longer need _anotherService you can call Dispose() method of it directly like

    _anotherService.Dispose() ;
    


    Once you dispose it, that object and the bound lifetimescope and any other child or dependant object of that lifetimescope will be gone and released. So you would not have to bear the unnecessary presence of _anotherService and it's loads of dependent components

    So our constructor part of the MyService should be like following:

        private readonly Owned<IAnotherService> _anotherService;
    
        public MyService(Owned<IAnotherService> anotherService)
        {
            _anotherService = anotherService;
        }
    

    InstancePerOwned

    Meaning that we have a lifetimescope bound to the anotherService which anotherService is instantiated within. If you want to force all the newly created objects and resolved components inside above lifetimescope to share the same instance of anotherService then you have to use InstancePerOwned at the time of registration like this

     builder.RegisterType<AnotherService>().As<IAnotherService>().InstancePerOwned<IAnotherService>();
    


    and once you register AnotherService as InstancePerOwned you cannot pass pure IAnotherInstance and you will have to pass it like Owned or else you get exception.




    you can read more of this on An Autofac Lifetime Primer

    EDIT: Fixed one-character typo (edits must be at least 6 characters!)