Search code examples
c#asp.net-mvcinversion-of-controlautofacioc-container

Autofac Resolve an object which is not in Presentation Layer


I am using Autofac to resolve objects and I dont want to use constructor injection everytime in classes. Therefore I defined a base class but property injection didn't solve my problem. Everytime when I tried to reach this property on my base class from derived class, It is null.

For an example

public abstract class Service
{
    public static IUnitOfWork _unitOfWork;
}

I have a base class which name is service.

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.Register(c => Service.UnitOfWork = c.Resolve<IUnitOfWork>());

And my registration like on above.

I have two question about it,

  1. Can defining UnitOfWork property as static be dangerous?
  2. How can I resolve IUnitOfWork easily?

Solution

  • You definitely should consider the costructor injection pattern again and folow the advice of Mark. However to make your approach work you can do something like this:

    public static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
        builder.RegisterType<ServiceImpl>().As<Service>()
            .OnActivated(e => Service.UnitOfWork = e.Context.Resolve<IUnitOfWork>());
        var container = builder.Build();
        var service = container.Resolve<Service>();
        Console.WriteLine(Service.UnitOfWork);
        Console.ReadKey();
    } 
    

    Here ServiceImpl is a derived type from Service. As for your first question, public static fields are global variables, it is not a good idea(at all) to store UnitOfWork in this way. Moreover the whole idea of UnitOfWork contradicts with that. At least it would be better to make UnitOfWork instance property, protected it of assigning more then once and dispose it explicitlyin ServiceImpl.Dispose.

    UPD: Additional example for instance property injection approach:

    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
            builder.RegisterType<ServiceImpl>().As<Service>()
                .OnActivated(e => e.Instance.UnitOfWork = e.Context.Resolve<IUnitOfWork>());
            var container = builder.Build();
            var service = container.Resolve<Service>();
            Console.WriteLine(service.IsUnitOfWorkInjected);
            Console.ReadKey();
        }
    }
    
    public abstract class Service : IDisposable
    {
        private IUnitOfWork _unitOfWork;
        private static readonly object padlock = new object();
    
        public IUnitOfWork UnitOfWork
        {
            protected get => _unitOfWork;
            set
            {
                if (_unitOfWork == null)
                {
                    lock (padlock)
                    {
                        if (_unitOfWork == null)
                        {
                            _unitOfWork = value;
                        }
                    }
                }
            }
        }
    
        public bool IsUnitOfWorkInjected => UnitOfWork != null;
    
        public void Dispose()
        {
            _unitOfWork?.Dispose();
        }
    } 
    

    Hope it helps.