Enter directly or indirectly depending on yourself. Simple injector

I want to create a caching service that receives a regular service as a constructor parameter. Then, when the cache key does not exist, I want to call the regular maintenance and update cache. My idea is to have the same interface in a regular service and cache. But when I try to implement the implementation of the caching service and execute the method, I get an exception:

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

My code is:

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 is 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 is my root of the composition:

 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); } } 
+6
source share
1 answer

What happens: You registered the CacheUserRepository class by the type of its IUserRepository service. This means that every time someone asks for an IUserRepository (either by calling GetInstance<IUserRepository>() or by requiring an argument to the IUserRepository constructor), Simple Injector will provide them with a new instance of CacheUserRepository .

So far, so good, but CacheUserRepository itself contains an argument to the IUserRepository constructor. This will cause Simple Injector to provide your CacheUserRepository new instance of CacheUserRepository . And of course, this new instance comes again with the new CacheUserRepository instance. Since this will result in a stackoverflow exception, Simple Injector will prevent this and throw an exception that you saw.

Your CacheUserRepository is actually a decorator. A simple injector supports decorator handling. Your registration will look like this:

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

The RegisterDecorator method is careful about circular dependency and ensures that Simple Injector will not chase its tail.

+7
source

Source: https://habr.com/ru/post/989854/


All Articles