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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With