Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type directly or indirectly depending on itself Simple Injector

I want to create Cache service which get regular service as constructor parameter. Then when cache key does not exist I want to call regular service and update cache. My idea is to have the same interface in regular service and cache service. But when I'm trying to inject cache service implementation and execute method I get exception:

The registered delegate for type IUserRepository threw an exception. The configuration is invalid. The type CacheUserRepository is directly or indirectly depending on itself.

My code:

public interface IUserRepository
{
    UserDTO Get(int userId);
}

public class UserRepository : IUserRepository
{
    public virtual UserDTO Get(int userId)
    {
            return new UserDTO() { Id = 1, Age = 28, Name = "Emil" };
    }
}      

Here's my cache repository:

public class CacheUserRepository : IUserRepository
{
    private readonly IUserRepository _userRepository;
    private readonly ICache _cache;

    public CacheUserRepository(IUserRepository userRepository, ICache cache)
    {
            _userRepository = userRepository;
            _cache = cache;
    }

    public DTO.UserDTO Get(int userId)
    {
            var userKey = "User_" + userId.ToString();

            UserDTO val = _cache.Get<UserDTO>(userKey);

            if (val != null)
                    return val;

            UserDTO user = _userRepository.Get(userId);
            _cache.Add(userKey, user);

            return user;
    }
}

Here's my composition root:

public class ExecutionClass
{
    private readonly Container _container;

    public ExecutionClass()
    {
        _container = new Container();

        _container.Register<IUserRepository, CacheUserRepository>();
        _container.Register<ICache, Cache>();
    }

    public UserDTO GetUser(int Id)
    {
        //throws: The type CacheUserRepository is directly or indirectly depending
        // on itself.
        var userRepo = _container.GetInstance<IUserRepository>(); \
        return userRepo.Get(Id);
    }
}
like image 459
Emil Avatar asked Jun 27 '15 11:06

Emil


1 Answers

What is happening is the following: You registered the CacheUserRepository class by its service type IUserRepository. This means that everytime anyone requests an IUserRepository (either by calling GetInstance<IUserRepository>() or by requiring an IUserRepository as constructor argument), Simple Injector will supply it with a new CacheUserRepository instance.

So far so good, but the CacheUserRepository itself contains a constructor argument of IUserRepository. This will lead Simple Injector to supply your CacheUserRepository with a new CacheUserRepository instance. And of course this new instance gets again supplied with a new CacheUserRepository instance. Since this would cause a stackoverflow exception, Simple Injector prevents this and throws the exception you saw.

Your CacheUserRepository is in fact a decorator. Simple Injector has support for handling decorators. This is how your registration should look like:

container.Register<IUserRepository, UserRepository>();
container.RegisterDecorator<IUserRepository, CacheUserRepository>();

The RegisterDecorator method takes special care of the cyclic dependency and will make sure that Simple Injector will not chase its tail.

like image 130
Steven Avatar answered Sep 30 '22 12:09

Steven