21

I have a model:

public class Checkout
{
    public string CheckoutId { get; set; }

    public List<CheckoutItem> CheckoutItems { get; set; }

}

And I am trying to add methods to the Object while respecting POCOs. So I added A repository:

    public class CheckoutRepository : ICheckoutRepository
    {
        private readonly AppDbContext _appDbContext;
        private readonly Checkout _checkout;

        public CheckoutRepository(AppDbContext appDbContext, Checkout checkout)
        {
            _appDbContext = appDbContext;
            _checkout = checkout;

        }

        public void AddItem(unitItem item, int amount)
        {
              //Removed for brevity 
        }

        public void ClearCheckout()
        {
           //Details removed for brevity
        }

        public Checkout GetCart(IServiceProvider serviceProvider)
        {   
          //Details removed for brevity
        }

        public List<CheckoutItem> GetCheckoutItems()
        {
            //Details removed for brevity
        }

        public decimal GetCheckoutTotal()
        {
           //Details removed for brevity
        }

        public decimal RemoveItem(unitItem item)
        {
           //Details removed for brevity
        }

And an interface to the Repository

public interface ICheckoutRepository
    {
         Checkout GetCart(IServiceProvider serviceProvider);

        void AddItem(unitItem item, int amount);

        decimal RemoveItem(unitItem item);

        List<CheckoutItem> GetCheckoutItems();

        void ClearCheckout();

        decimal GetCheckoutTotal();
    }

I, of course, add this to the startup file.

services.AddTransient<ICheckoutRepository, CheckoutRepository>();

But when I run the application I get the error

System.AggregateException: 'Some services are not able to be constructed'

And 2 inner exceptions

1:

InvalidOperationException: Error while validating the service descriptor 'ServiceType: BataCMS.Data.Interfaces.ICheckoutRepository Lifetime: Transient ImplementationType: BataCMS.Data.Repositories.CheckoutRepository': Unable to resolve service for type 'BataCMS.Data.Models.Checkout' while attempting to activate 'BataCMS.Data.Repositories.CheckoutRepository'.

And 2:

InvalidOperationException: Unable to resolve service for type 'BataCMS.Data.Models.Checkout' while attempting to activate 'BataCMS.Data.Repositories.CheckoutRepository'

Could really use some insight into this problem.

David Liang
  • 20,385
  • 6
  • 44
  • 70
Paul Gudu
  • 363
  • 1
  • 3
  • 10
  • 4
    You are passing `Checkout checkout` in constructor, so you need either remove it from there or register it in the DI container. – Guru Stron Jul 29 '20 at 14:26
  • Please check this article i facing this issue https://stackoverflow.com/questions/74051242/dbinizializer-register-in-program-in-net6-core-6-0-9 – Muhammad Asad Oct 14 '22 at 07:33

3 Answers3

24

When you look at your CheckoutRepository constructor, you'll see that you're injecting an instance of a Checkout class. ASP.NET doesn't know where to search for an instance of that class to inject, so you have to register it in your DI container.

Add this to your Startup file:

services.AddTransient<Checkout>(new Checkout());

This is a little bit different type of registering. Instead of depending on abstraction, you're depending on a concrete implementation of Checkout class. I've passed a default, parameterless constructor to the above example, but you can pass any other constructor to it, or (to depend on an abstraction) just create the ICheckout interface and register just like you registered the ICheckoutRepository:

services.AddTransient<ICheckout, Checkout>();

More on DI can be found here

I also explore the practical approach to it in this video

Duck Ling
  • 1,577
  • 13
  • 20
  • Much appreciated thank you for the solution and explanation, just to clarify about the DI, Is it bad practice to inject the concrete class. Do I have to have some level abstraction using the `ICheckout` interface. But otherwise the solution works fine. Thanks again. – Paul Gudu Jul 29 '20 at 21:09
  • 2
    Hey Paul. No problem. Think about it this way: One day, you decide to add another checkout method, but your `ICheckoutRepository` only accepts one type of checkout (the concrete `Checkout` class) and the inner workings of any type of `ICheckoutRepository` (there can be many since it's an interface) depend on that class, so adding another one may become painful. If you introduce the `ICheckout` interface, you'll be able to construct that repo with any implementation of `ICheckout`. It also comes in handy when mocking while testing. Read up on dependency inversion principle :) – Duck Ling Jul 29 '20 at 22:48
2

Maybe you missing?

services.AddTransient<ICheckout, Checkout>();

Hope I helped.

Sergei
  • 195
  • 6
1

This was because I declared in IRepo as IEnumerable and passed a list from repo.

Fixing this has fixed my issues

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459