'How to use MemoryCache in C# Core Console app?

I would like to use the Microsoft.Extensions.Caching.Memory.MemoryCache in a .NET Core 2.0 console app (Actually, in a library that is either used in a console or in a asp.net app)

I've created a test app:

using System;

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var cache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());

            int count = cache.Count;
            cache.CreateEntry("item1").Value = 1;
            int count2 = cache.Count;
            cache.TryGetValue("item1", out object item1);
            int count3 = cache.Count;
            cache.TryGetValue("item2", out object item2);
            int count4 = cache.Count;

            Console.WriteLine("Hello World!");
        }
    }
}

Unfortunately, this is not working. The items are not added to the cache and they can not be retrieved.

I suspect I need to use DependencyInjection, doing something like this:

using System;
using Microsoft.Extensions.DependencyInjection;

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var provider = new Microsoft.Extensions.DependencyInjection.ServiceCollection()
                .AddMemoryCache()
                .BuildServiceProvider();

            //And now?

            var cache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());

            var xxx = PSP.Helpers.DependencyInjection.ServiceProvider;
            int count = cache.Count;
            cache.CreateEntry("item1").Value = 1;
            int count2 = cache.Count;
            cache.TryGetValue("item1", out object item1);
            int count3 = cache.Count;
            cache.TryGetValue("item2", out object item2);
            int count4 = cache.Count;

            Console.WriteLine("Hello World!");
        }
    }
}

Unfortunately, this is also not working, I suspect I shouldn't create a new memory cache, but get it from the service provider, but haven't been able to do that.

Any ideas?



Solution 1:[1]

After configuring the provider retrieve the cache via the GetService extension method

var provider = new ServiceCollection()
                       .AddMemoryCache()
                       .BuildServiceProvider();

//And now?
var cache = provider.GetService<IMemoryCache>();

//...other code removed for brevity;

From comments:

It's not needed to use dependency injection, the only thing needed was disposing the return value of CreateEntry(). The entry returned by CreateEntry needs to be disposed. On dispose, it is added to the cache:

using (var entry = cache.CreateEntry("item2")) { 
    entry.Value = 2; 
    entry.AbsoluteExpiration = DateTime.UtcNow.AddDays(1); 
}

Solution 2:[2]

IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());
object result = cache.Set("Key", new object());
bool found = cache.TryGetValue("Key", out result);

See full Memory Cache Sample in GitHub.

You need to add NuGet Microsoft.Extensions.Caching.Memory packages in your project for use MemoryCache

Solution 3:[3]

Here is the complete console application code in .NET Core

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using System;

using System.Threading;

namespace InMemoryNetCore
{
   class Program
  {
      static void Main(string[] args)
     {
        IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());
        object result;
        string key = "KeyName";
  

        // Create / Overwrite
        result = cache.Set(key, "Testing 1");
        result = cache.Set(key, "Update 1");

        // Retrieve, null if not found
        result = cache.Get(key);
        Console.WriteLine("Output of KeyName Value="+result);

        // Check if Exists
        bool found = cache.TryGetValue(key, out result);

        Console.WriteLine("KeyName Found=" + result);

        // Delete item
        cache.Remove(key);


        //set item with token expiration and callback
        TimeSpan expirationMinutes = System.TimeSpan.FromSeconds(0.1);
        var expirationTime = DateTime.Now.Add(expirationMinutes);
        var expirationToken = new CancellationChangeToken(
            new CancellationTokenSource(TimeSpan.FromMinutes(0.001)).Token);

        // Create cache item which executes call back function
        var cacheEntryOptions = new MemoryCacheEntryOptions()
       // Pin to cache.
       .SetPriority(Microsoft.Extensions.Caching.Memory.CacheItemPriority.Normal)
       // Set the actual expiration time
       .SetAbsoluteExpiration(expirationTime)
       // Force eviction to run
       .AddExpirationToken(expirationToken)
       // Add eviction callback
       .RegisterPostEvictionCallback(callback: CacheItemRemoved);
        //add cache Item with options of callback
        result = cache.Set(key,"Call back cache Item", cacheEntryOptions);


        Console.WriteLine(result);



        Console.ReadKey();

    }

    private static void CacheItemRemoved(object key, object value, EvictionReason reason, object state)
    {
        Console.WriteLine(key + " " + value + " removed from cache due to:" + reason);
      }
   }
}

Source : In Memory cache C# (Explanation with example in .NET and .NET Core)

Solution 4:[4]

To the responses above, I wanted to add some concise alternatives for common cache operations:

using Microsoft.Extensions.Caching.Memory;

// ... (further down) ...
MemoryCache cache = new MemoryCache(new MemoryCacheOptions() );

// get a value from the cache
// both are equivalent
// obviously, replace "string" with the correct type
string value = (string)cache.Get("mykey");
string value = cache.Get<string>("mykey");

// setting values in the cache
// no expiration time
cache.Set("mykey", myVar);

// absolute expiration numMinutes from now
cache.Set("mykey", myVar, DateTimeOffset.Now.AddMinutes(numMinutes));

// sliding expiration numMinutes from now
// "sliding expiration" means that if it's accessed within the time period,
//      the expiration is extended
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.SetSlidingExpiration(TimeSpan.FromMinutes(numMinutes));
webcache.Set("mykey", myVar, options);

// or, if you want to do it all in one statement:
webcache.Set("mykey", myVar, 
    new MemoryCacheEntryOptions {SlidingExpiration = TimeSpan.FromMinutes(numMinutes)});

Solution 5:[5]

In the context of an AutomaticTest for a Asp net core controller I allocate an instance of MemoryCache in the test preparation Setup like below:

    TestCaseController _sut;
    long? NO_SIZE_LIMIT = null;

    [SetUp]
    public void Setup()
    {
        var options = new MemoryCacheOptions() 
        { 
            Clock = new SystemClock(), 
            CompactionPercentage = 1, 
            ExpirationScanFrequency = TimeSpan.FromSeconds(100), 
            SizeLimit = NO_SIZE_LIMIT
        };
        IOptions<MemoryCacheOptions> optionsAccessor = Options.Create(options);
        IMemoryCache memoryCache= new MemoryCache(optionsAccessor);
        _sut = new TestCaseController(memoryCache);
    }

The Target Controller then use the cache like this:

    [HttpGet("Active")]
    public IEnumerable<TestCase> GetActive()
    {
        LogRequest();
        IEnumerable<TestCase> ret;
        var cacheKey = "TestCaseActive";
        if (!_memoryCache.TryGetValue(cacheKey, out ret))
        {
            ret = _dbRepo.GetActive();
            var cacheExpiryOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddSeconds(60),
                Priority = CacheItemPriority.High,
                SlidingExpiration = TimeSpan.FromSeconds(50)
            };
            _memoryCache.Set(cacheKey, ret, cacheExpiryOptions);
        }
        else
        {
            _log.Debug("Fetch Cache");
        }
        _log.Debug(ret.Count() + " items returned");
        return ret;
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Stanislav Prusac
Solution 3 Vikas Lalwani
Solution 4 Patrick Chu
Solution 5