asp.net-web-apidryioc

DryIOC service registered as singleton but new instance is being injected per request


We have a class in our .net6 WebAPI project used for two-level caching. We inject two instances of an ICacheClient interface, one used for short-term caching and one used for long-term. One of the caches is configured as a singleton, but it is injecting a new instance for every request. The container is set up like so:

public static void RegisterDependencies(this IContainer container)
{
    container.Register<StackExchangeRedisCacheClient>(Reuse.Singleton, Made.Of(() => new StackExchangeRedisCacheClient(Arg.Of<ISerializer>(), Arg.Of<IOptions<ConnectionStrings>>())));
    container.Register<TwoLevelCacheClient>(Made.Of(() => new TwoLevelCacheClient(Arg.Of<MemoryCacheClient>(), Arg.Of<StackExchangeRedisCacheClient>())));
}

The TwoLevelCacheClient just takes a two ICacheClient parameters:

public class TwoLevelCacheClient : ITwoLevelCacheClient
{
    public TwoLevelCacheClient(ICacheClient firstLevelCacheClient, ICacheClient secondLevelCacheClient)
    {
        ...
    }
}

Even though the StackExchangeRedisCacheClient is set as a singleton, a new instance is injected into the TwoLevelCacheClient for every request. The TwoLevelCacheClient is configured as transient lifetime.

I wasn't sure if it was because the MadeOf parameter is being used as a factory function, so I tried using reflection to specify the constructor instead, but it made no difference. The dryIoc docs indicate this function is never run

Note: The code () => new Foo(Arg.Of<IDependency>() is just a specification expression and won't be executed

https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/SelectConstructorOrFactoryMethod.cs

Edit: I have also tried registering a single client using that with a service key, but that also doesn't appear to work:

    public static void RegisterDependencies(this IContainer container)
    {            
        var redisCacheClient = new StackExchangeRedisCacheClient(container.Resolve<ISerializer>(), container.Resolve<IOptions<ConnectionStrings>>());
        container.RegisterInstance(redisCacheClient, serviceKey: "redisCacheClient");

        container.Register<StackExchangeRedisCacheClient>(Reuse.Singleton, Made.Of(() => new StackExchangeRedisCacheClient(Arg.Of<ISerializer>(), Arg.Of<IOptions<ConnectionStrings>>())));
        container.Register<TwoLevelCacheClient>(Made.Of(() => new TwoLevelCacheClient(Arg.Of<MemoryCacheClient>(), Arg.Of<StackExchangeRedisCacheClient>("redisCacheClient"))));
    }

Solution

  • The problem was in the line container.Register<TwoLevelCacheClient>(Made.Of(() => new TwoLevelCacheClient(Arg.Of<MemoryCacheClient>(), Arg.Of<StackExchangeRedisCacheClient>("redisCacheClient"))));, however it was being injected as ITwoLevelCacheClient, so was ignoring the binding. D'oh