Search code examples
c#autofacrepository-pattern

Circular component dependency detected Repository pattern with autofac dependency injections


I am working on implementing the generic repository pattern with db Context and Autofac DI, and I am using the constructor based on dependency injections.

I have created the three layers repository pattern which are:

  • Infrastructure layer
  • Model layer
  • Services layer

Now, I am using this architecture in MVC web application when I try to pass the IContactService interface in ContactController and run the application.

I am getting the circular dependency detected error. Followings are my project code.

error

Repository code:

public class Repository<T> : IRepository<T> where T : class
{
    private InvoiceBillingDbContext db;
    private DbSet<T> dbSet;

    public Repository()
    {
        db = new InvoiceBillingDbContext();
        dbSet = db.Set<T>();
    }
    public IEnumerable<T> GetAll()
    {
        return dbSet.ToList();
    }

    public T GetById(object Id)
    {
        return dbSet.Find(Id);
    }

    public void Insert(T obj)
    {
        dbSet.Add(obj);
        Save();
    }
    public void Update(T obj)
    {
        db.Entry(obj).State = EntityState.Modified;
        Save();
    }
    public void Delete(object Id)
    {
        T getObjById = dbSet.Find(Id);
        dbSet.Remove(getObjById);
    }
    public void Save()
    {
        db.SaveChanges();
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (this.db != null)
            {
                this.db.Dispose();
                this.db = null;
            }
        }
    }

    public void AddRange(List<T> obj)
    {
        dbSet.AddRange(obj);
        Save();
    }

    public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
    {
        return dbSet.Where(predicate);
    }
}

Interface IRepository

public interface IRepository<T> where T : class
{
        IEnumerable<T> GetAll();
        T GetById(object Id);
        IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
        void Insert(T obj);
        void AddRange(List<T> obj);
        void Update(T obj);
        void Delete(Object Id);
        void Save();
}

My ContactRepository

public class ContactRepository:Repository<Contact>, IContactRepository
{
        private IContactRepository _contractRepo;
        public ContactRepository(IContactRepository contractRepo)
        {
            this._contractRepo = contractRepo;
        }
}

My ContactRepository Interface

public interface IContactRepository:IRepository<Contact>
{
}

My Contact Service

public interface IContactService
{
        void AddContact(Contact contact);
        IEnumerable<Contact> GetContactsByTypeId(int typeId);
}

public class ContactService : IContactService
{
        private readonly IContactRepository _contactRepository;
        public ContactService(IContactRepository contactRepository)
        {
            this._contactRepository = contactRepository;
        }
        public void AddContact(Contact contact)
        {
            _contactRepository.Insert(contact);
        }

        public IEnumerable<Contact> GetContactsByTypeId(int typeId)
        {
            return _contactRepository.Get(i => i.TypeID == typeId);
        }
}

My Controller

public class ContactController : Controller
{
        // GET: Contact
        private IContactService _contactService;

        public ContactController(IContactService contactService)
        {
            this._contactService = contactService;
        }
        public ActionResult Index()
        {
            return View(new ContactViewModel());
        }

        public ActionResult AddContact(ContactViewModel contact)
        {
            if (ModelState.IsValid)
            {
                var _contactMapper = Mapper.Map<ContactViewModel, Contact>(contact);
                _contactService.AddContact(_contactMapper);
                ViewBag.Message = "Successfully Saved";
                return View("Index",new ContactViewModel());
            }
            ViewBag.Message = "Error Occur Please try Again!";
            return View("Index", new ContactViewModel());
        }
}

And Autofac Dependency Injection

public static void ConfigureContainer()
{
            var builder = new ContainerBuilder();

            // Register all controllers in the Mvc Application assembly
            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            // Registered Warehouse Reservoir Service
            builder.RegisterType<InvoiceRepository>().As<IInvoiceRepository>();
            // Registration Service Layer Service
            builder.RegisterType<InvoiceService>().As<IInvoiceService>();
            builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
            // Registered Warehouse Reservoir Service
            builder.RegisterType<JournalVoucherRepository>().As<IJournalVoucherRepository>();
            // Registration Service Layer Service
            builder.RegisterType<JournalVoucherService>().As<IJournalVoucherService>();



            // Registered Warehouse Reservoir Service
            builder.RegisterType<ContactRepository>().As<IContactRepository>();
            // Registration Service Layer Service
            builder.RegisterType<ContactService>().As<IContactService>();




            // Registration filter
            builder.RegisterFilterProvider();

            var container = builder.Build();

            // Setting Dependency Injection Parser
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

Solution

  • You've only got one implementation of IContactRepository. You've also got a generic IRepository<T>.

    Your implementation of IContactRepository gets another IContactRepository injected into it. So you're recursively resolving the same class and injecting it into itself.

    public class ContactRepository:Repository<Contact>, IContactRepository
    {
            private IContactRepository _contractRepo;
    
            // In order to resolve IContractRepository, the container has to 
            // resolve another IContractRepository to inject into it. 
            // And another one to inject into that. It's recursive.
            public ContactRepository(IContactRepository contractRepo)
            {
                this._contractRepo = contractRepo;
            }
    }
    

    Your example doesn't show how ContactRepository uses the IContactRepository that gets inject into it. But this

    public interface IContactRepository:IRepository<Contact>
    {
    }
    

    reveals that it's using the exact same methods found in IRepository<Contact>, because IContactRepository doesn't have any methods other than those.

    So you most likely just need to modify ContactRepository to inject IRepository<Contact>, not IContactRepository.

    public class ContactRepository:Repository<Contact>, IContactRepository
    {
            private IRepository<Contact> _contractRepo;
    
            public ContactRepository(IRepository<Contact> contractRepo)
            {
                this._contractRepo = contractRepo;
            }
    }
    

    That could be easy to overlook since both interfaces have exactly the same methods.