2

I have a problem with IAfterSaleService interface and AfterSaleService Class and I used autofac IoC for these cs files. However while constructor injection ı made is working for some interface, aftersaleservice is not working for some constructor injection. For example, While IAfterService works in the constructor of AfterServiceController, it does not work in the constructor of other service(like OrderService.cs...) in the same directory

I am getting following exception response

Autofac.Core.DependencyResolutionException: An exception was thrown while activating Retail.Business.Concretes.AfterSaleService -> Retail.Business.Concretes.OrderService. ---> Autofac.Core.DependencyResolutionException: Circular component dependency detected: Retail.Business.Concretes.AfterSaleService -> Retail.Business.Concretes.OrderService -> Retail.Business.Concretes.AfterSaleService.

With the following stack trace:

   at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
   at Autofac.Core.Resolving.Pipeline.DefaultResolveRequestContext.ResolveComponent(ResolveRequest request)
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass0_0.<CanSupplyValue>b__0()
   at Autofac.Core.Activators.Reflection.BoundConstructor.Instantiate()
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext ctxt, Action`1 next)
   at Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   --- End of inner exception stack trace ---
   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Middleware.SharingMiddleware.<>c__DisplayClass5_0.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid id, Func`1 creator)
   at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid primaryId, Nullable`1 qualifyingId, Func`1 creator)
   at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
   at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
   at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request)
   at Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest request)
   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest request)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
   at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)
   at Autofac.Extensions.DependencyInjection.AutofacServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method429(Closure , IServiceProvider , Object[] )
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)   

My IoC Like as follows. I said that IAfterService does not work in the constructor of following services

public class ContainerModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {

        builder.RegisterType<AfterSaleService>().As<IAfterSaleService>().SingleInstance();
        builder.RegisterType<EfAfterSaleDal>().As<IAfterSaleDal>().SingleInstance();

        builder.RegisterType<ProductService>().As<IProductService>().SingleInstance();
        builder.RegisterType<EfProductDal>().As<IProductDal>().SingleInstance();

        builder.RegisterType<CustomerService>().As<ICustomerService>().SingleInstance();
        builder.RegisterType<EfCustomerDal>().As<ICustomerDal>().SingleInstance();

        builder.RegisterType<OrderService>().As<IOrderService>().SingleInstance();
        builder.RegisterType<EfOrderDal>().As<IOrderDal>().SingleInstance();

        builder.RegisterType<EfOrderDetailDal>().As<IOrderDetailDal>().SingleInstance();
        builder.RegisterType<OrderDetailService>().As<IOrderDetailService>()
            .SingleInstance();
    }
}

But it works in the constructor of controllers

private IAfterSaleService _afterSaleService;

public AfterSalesController(IAfterSaleService afterSaleService)
{
    _afterSaleService = afterSaleService;
}

and it does not work following service same directory with AfterService.cs and I want it to work this in OrderService.cs because ı need it Note: other services(like ICustomerService, IProductService...) works in the constructor of OrderService only IAfterSaleService does not work

    public class OrderService : IOrderService
    {
        private IOrderDal _orderDal;
        private ICustomerService _customerService;
        private IProductService _productService;
        private IOrderDetailService _orderDetailService;
        private IAfterSaleService _afterSaleService;

        public OrderService(
            IOrderDal orderDal,
            ICustomerService customerService,
            IProductService productService,
            IOrderDetailService orderDetailService,
            IAfterSaleService afterSaleService)
        {
            _orderDal = orderDal;
            _customerService = customerService;
            _productService = productService;
            _orderDetailService = orderDetailService;
            _afterSaleService = afterSaleService;
        }
    }

AfterService.cs

    public class AfterSaleService : IAfterSaleService
    {
        private IAfterSaleDal _afterSaleDal;
        private IOrderService _orderService;

        public AfterSaleService(
            IAfterSaleDal afterSaleDal, IOrderService orderService)
        {
            _afterSaleDal = afterSaleDal;
            _orderService = orderService;
        }
    }
Steven
  • 166,672
  • 24
  • 332
  • 435
notcontrol
  • 109
  • 1
  • 8
  • And code for `IAfterSaleService` implementation's ctor is? – Guru Stron Oct 09 '21 at 21:14
  • please add code to the question. – Guru Stron Oct 09 '21 at 21:25
  • ı added code for IAfterSaleService implementation's ctor – notcontrol Oct 09 '21 at 21:33
  • In [section 6.3](https://livebook.manning.com/book/dependency-injection-principles-practices-patterns/chapter-6/section-6-3?origin=product-toc) of [DIPP&P](https://cuttingedge.it/book/), Mark Seemann and I argue that Cyclic Dependencies are often caused by [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) violations. After seeing the name and the number of dependencies of `OrderService`, I believe your Cyclic Dependency is caused by a SRP violation as well. You might want to consider splitting `OrderService` up into multiple smaller services. – Steven Oct 11 '21 at 08:24

1 Answers1

1

The error is pretty clear:

Circular component dependency detected

Your AfterSaleService depends on IOrderService and OrderService depends on IAfterSaleService which for obvious reasons will make it impossible for DI container to resolve the dependencies during construction. Personally I try not to inject dependencies of the same "level", i.e. repositories does not accept repositories, services - services and controllers do not depend on the other controllers so my recommendation would be to refactor your application so you don't need such injections (maybe introduce one more layer or move common code to static helpers or something else).

If it is not feasible ATM to rewrite due to amount of work you can use work around the issue for now - inject same level dependencies as Func's. Autofac provides Func resolutions out of the box (i.e. if you register IService you can resolve Func<IService> without any extra registrations), so you can do something like this:

public OrderService(..., Func<IAfterSaleService> afterSaleServiceFactory)
{
    .... 
    _afterSaleService = new Lazy<IAfterSaleService>(afterSaleServiceFactory);
}

And

public AfterSaleService(IAfterSaleDal afterSaleDal, 
     Func<IOrderService> orderServiceFactory)
{
    _afterSaleDal = afterSaleDal;
    _orderService = new Lazy<IAfterSaleService>(orderServiceFactory);
}

And use lazily resolved dependencies - _afterSaleService .Value, _orderService.Value

UPD

Actually it seems that Autofac also supports Lazy out of the box so this can be even easier:

public OrderService(..., Lazy<IAfterSaleService> afterSaleServiceFactory)
{
    .... 
    _afterSaleService = afterSaleService;
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Yes, thank you very much. I understand my mistake. I will change my design. but ı do not understand how is work func – notcontrol Oct 09 '21 at 21:41
  • @notcontrol you inject factory (func) not the dependecy itself, so it is resolved when you need to use it (i.e. when you need the `_afterSaleService` you call `_afterSaleServiceFactory` or init the lazy value), not at the time of construction of the service. You can still have an issues with such design though (i.e. if some method in A will need to call B which will need to call A, which will need to call B ... you will end up with SO) but in my experience usually it does not happen. – Guru Stron Oct 09 '21 at 23:40