entity-frameworkdependency-injectionentity-framework-coreautofacunit-of-work

I can't inject my IUnitOfWork class into my ApartmentManager class


I'm building an apartment dues management system. Below are my related classes. If I inject my IUnitOfWork class in my ApartmentManager class and pass it in ctor it gives the following error.

mistake:

Autofac.Core.DependencyResolutionException: An exception was thrown while activating Business.Concrete.ApartmentManager -> DataAccess.Concrete.UnitOfWork.UnitOfWork.

---> Autofac.Core.DependencyResolutionException: None of the constructors found on type 'DataAccess.Concrete.UnitOfWork.UnitOfWork' can be invoked with the available services and parameters:

Cannot resolve parameter 'DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext context' of constructor 'Void .ctor(DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext)'.
Classes:

public class AutofacBusinessModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>()
            .InstancePerLifetimeScope();
        builder.RegisterType<EfApartmentDal>().As<IApartmentDal>()
            .InstancePerLifetimeScope();
        builder.RegisterType<ApartmentManager>()
            .As<IApartmentService>()
            .InstancePerLifetimeScope();
    }
}
public interface IUnitOfWork
    {
        Task CommitAsync();
        void Commit();
        //Task<int> SaveChangesAsync();
        //Task BeginTransactionAsync();
        //Task CommitTransactionAsync();
        //Task RollbackTransactionAsync();

        //public interface IEntityRepository<T> where T : class, IEntity, new()
        //{
        //    Task AddRangeAsync(IEnumerable<T> entities);
        //}

        //public interface IApartmentRepository : IEntityRepository<Apartment> { }
    }
 public class UnitOfWork : IUnitOfWork
    {
        private readonly ApartmentDuesManagementContext _context;
        //private IDbContextTransaction _transaction;
        public UnitOfWork(ApartmentDuesManagementContext context)
        {
            _context = context;
        }
        public void Commit()
        {
            _context.SaveChanges();
        }

        public async Task CommitAsync()
        {
            await _context.SaveChangesAsync();
        }
}
public class EfApartmentDal : EfEntityRepositoryBase<Apartment, ApartmentDuesManagementContext>, IApartmentDal
    {
       
    }
public interface IApartmentDal : IEntityRepository<Apartment>
    {
        
    }
public interface IApartmentService
    {
        IDataResult<List<Apartment>> GetList();
        Task<IDataResult<Task<IEnumerable<Apartment>>>> AddRangeAsync<TEntity>(IEnumerable<Apartment> apartments);
    }
public class ApartmentManager : IApartmentService
    {
        private readonly IApartmentDal _apartmentDal;
        private readonly IUnitOfWork _unitOfWork;
        public ApartmentManager(IApartmentDal apartmentDal, IUnitOfWork unitOfWork)
        {
            _apartmentDal = apartmentDal;
            _unitOfWork = unitOfWork;
        }

        public IDataResult<List<Apartment>> GetList()
        {
            return new SuccessDataResult<List<Apartment>>(_apartmentDal.GetList(), "Apartmanlar basarili bir sekilde listelendi.");
        }

        public async Task<IDataResult<Task<IEnumerable<Apartment>>>> AddRangeAsync<TEntity>(IEnumerable<Apartment> apartments)
        {
            await _apartmentDal.AddRangeAsync(apartments);
            await _unitOfWork.CommitAsync();
            return new SuccessDataResult<Task<IEnumerable<Apartment>>>(Task.FromResult(apartments), "Kayıt ekleme başarılı");
        }
    }

If I do not add the constructor in the manager class, the error disappears. but if I do it this way, I can't use it in the manager class, right? I would be very happy if anyone with a solution can help.

When I wanted to add 100 records in the Manager class, I was hoping that this would be done with the unit of work design pattern in a single operation to the database. but when I added this to my ApartmentManager class's constructor I got an error.


Solution

  • If you look at the error message, it should tell you what is wrong. The first line is:

    Autofac.Core.DependencyResolutionException: An exception was thrown while activating Business.Concrete.ApartmentManager -> DataAccess.Concrete.UnitOfWork.UnitOfWork.

    This means that Autofac tries to create an instance of Business.Concrete.ApartmentManager. It sees that it needs to create an instance of DataAccess.Concrete.UnitOfWork.UnitOfWork first. So it attempts to instantiate one.

    But in order to instantiate it, it sees it needs to have an instance of DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext, but it has no idea what that is or how to instantiate it.

    That is what the rest of the error message means:

    ---> Autofac.Core.DependencyResolutionException: None of the constructors found on type 'DataAccess.Concrete.UnitOfWork.UnitOfWork' can be invoked with the available services and parameters:

    Cannot resolve parameter 'DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext context' of constructor 'Void .ctor(DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext)'.

    So to solve it, you need to let Autofac know about DataAccess.Concrete.EntityFramework.Context.ApartmentDuesManagementContext. If you register this class when building the container, then Autofac can instantiate it:

    public class AutofacBusinessModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>()
                .InstancePerLifetimeScope();
            builder.RegisterType<EfApartmentDal>().As<IApartmentDal>()
                .InstancePerLifetimeScope();
            builder.RegisterType<ApartmentManager>()
                .As<IApartmentService>()
                .InstancePerLifetimeScope();
    
            // Add this line
            builder
                .RegisterType<ApartmentDuesManagementContext>()
                .InstancePerLifetimeScope();
        }
    }