Search code examples
c#dependency-injectionunity-containermemorycache

Unity Container - How to correctly resolve a parameterised MemoryCache that's registered as a singleton


Despite Unity container being deprecated, unfortunately I find myself having to use it since the current wpf codebase I'm working on has been dependent on it for years.

On the server side, I'm able to just do

public void ConfigureServices ( IServiceCollection services )
{
    ...
    services.AddMemoryCache (memoryCacheOptions =>
    {
        memoryCacheOptions.SizeLimit = 2;
        memoryCacheOptions.TrackStatistics = true;
    } 
}

and then start using my DI member in the constructor of a Manager class

public class ClassManager
{
    ...

    private readonly IMemoryCache memoryCache;
    
    ...
    
    public ClassManager ( ... , IMemoryCache memoryCache)
    {
        ...
        this.memoryCache = memoryCache;
        ...
    }

}

I'm looking to implement some light caching on my wpf client that uses the Unity Container for DI. I've been trying to inject MemoryCache like this

...
{
    this.Container.RegisterType<IMemoryCache, MemoryCache> (new ContainerControlledLifetimeManager ());
    var optionsAccessor = new MemoryCacheOptions
            {
                SizeLimit = 2,
                TrackStatistics = true
            };
    this.Container.Resolve<IMemoryCache> (new ParameterOverride[] { new ("optionsAccessor", optionsAccessor ) });
}

It seems that the type registering is fine but however when it comes to resolving it, I get an error that says

Unity.ResolutionFailedException: 'Resolution failed with error: Failed to select a constructor for Microsoft.Extensions.Caching.Memory.MemoryCache

For more detailed information run Unity in debug mode: new UnityContainer().AddExtension(new Diagnostic())'

InvalidOperationException: Failed to select a constructor for Microsoft.Extensions.Caching.Memory.MemoryCache

InvalidRegistrationException: Exception of type 'Unity.Exceptions.InvalidRegistrationException' was thrown.

Not sure what I'm doing wrong here, as the MemoryCache's ctor takes in an argument of IOptions<MemoryCacheOptions>, and I'm overriding the parameter to feed in a MemoryCacheOptions object, which already implements the <IOptions> interface.

You can find the MemoryCache ctor here: https://github.com/dotnet/extensions/blob/release/3.1/src/Caching/Memory/src/MemoryCache.cs


Solution

  • Just register using the factory method

        UnityContainer container = new UnityContainer();
    
        container.RegisterFactory<IMemoryCache>( 
            c =>
            {
                var optionsAccessor = new MemoryCacheOptions
                {
                    SizeLimit = 2,
                    TrackStatistics = true
                };
                return new MemoryCache( optionsAccessor );
            }, new ContainerControlledLifetimeManager() );
    
        var cache = container.Resolve<IMemoryCache>();