Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory Cache in dotnet core

I am trying to write a class to handle Memory cache in a .net core class library. If I use not the core then I could write

using System.Runtime.Caching;
using System.Collections.Concurrent;

namespace n{
public class MyCache
{
        readonly MemoryCache _cache;
        readonly Func<CacheItemPolicy> _cachePolicy;
        static readonly ConcurrentDictionary<string, object> _theLock = new ConcurrentDictionary<string, object>();

        public MyCache(){
            _cache = MemoryCache.Default;
            _cachePolicy = () => new CacheItemPolicy
            {
                SlidingExpiration = TimeSpan.FromMinutes(15),
                RemovedCallback = x =>    
                {
                    object o;
                    _theLock.TryRemove(x.CacheItem.Key, out o);
                }
            };
        }
        public void Save(string idstring, object value){
                lock (_locks.GetOrAdd(idstring, _ => new object()))
                {
                        _cache.Add(idstring, value, _cachePolicy.Invoke());
                }
                ....
        }
}
}

Within .Net core I could not find System.Runtime.Cache. After reading the .net core In Memory Cache, I have added reference Microsoft.Extensions.Caching.Memory (1.1.0) and tried

using System.Collections.Concurrent;
using Microsoft.Extensions.Caching.Memory;

namespace n
{
    public class MyCache
    {
            readonly MemoryCache _cache;
            readonly Func<CacheItemPolicy> _cachePolicy;
            static readonly ConcurrentDictionary<string, object> _theLock = new ConcurrentDictionary<string, object>();
            public MyCache(IMemoryCache memoryCache){
                   _cache = memoryCache;// ?? **MemoryCache**; 
            }

            public void Save(string idstring, object value){
                    lock (_locks.GetOrAdd(idstring, _ => new object()))
                    {
                            _cache.Set(idstring, value, 
                              new MemoryCacheEntryOptions()
                              .SetAbsoluteExpiration(TimeSpan.FromMinutes(15))
                              .RegisterPostEvictionCallback(
                                    (key, value, reason, substate) =>
                                    {
                                        object o;
                                        _locks.TryRemove(key.ToString(), out o);
                                    }
                                ));
                    }
                    ....
            }
    }
}

Hope code inside the save method is ok, although most of my mycache tests are failing at the moment. Can anyone please point out what is wrong? The main question is about the constructor What should i do to set the cache instead MemoryCache.Default

_cache = memoryCache ?? MemoryCache.Default; 
like image 627
MJK Avatar asked Jan 06 '17 12:01

MJK


People also ask

What is in-memory cache in .NET Core?

In-Memory Caching in ASP.NET Core is the simplest form of cache in which the application stores data in the memory of the webserver. This is based on the IMemoryCache interface which represents a cache object stored in the application's memory.

What is cache in .NET Core?

Caching makes a copy of data that can be returned much faster than from the source. Apps should be written and tested to never depend on cached data. ASP.NET Core supports several different caches. The simplest cache is based on the IMemoryCache. IMemoryCache represents a cache stored in the memory of the web server.

What is memory cache C#?

In-Memory Cache is used for when you want to implement cache in a single process. When the process dies, the cache dies with it. If you're running the same process on several servers, you will have a separate cache for each server. Persistent in-process Cache is when you back up your cache outside of process memory.

What is a memory cache?

Cache memory is a chip-based computer component that makes retrieving data from the computer's memory more efficient. It acts as a temporary storage area that the computer's processor can retrieve data from easily.


4 Answers

The constructor is:

using Microsoft.Extensions.Caching.Memory;

. . .

MemoryCache myCache = new MemoryCache(new MemoryCacheOptions());
like image 136
mattinsalto Avatar answered Oct 23 '22 10:10

mattinsalto


My answer is focused on the "Within .Net core I could not find System.Runtime.Cache", as I run into this same issue. For using IMemoryCache with the specific OP's scenario, the accepted answer is great.


There are two completely different caching implementations/solutions:

1 - System.Runtime.Caching/MemoryCache
2 - Microsoft.Extensions.Caching.Memory/IMemoryCache


System.Runtime.Caching/MemoryCache:
This is pretty much the same as the old day's ASP.Net MVC's HttpRuntime.Cache. You can use it on ASP.Net CORE without any dependency injection. This is how to use it:

// First install 'System.Runtime.Caching' (NuGet package)

// Add a using
using System.Runtime.Caching;

// To get a value
var myString = MemoryCache.Default["itemCacheKey"];

// To store a value
MemoryCache.Default["itemCacheKey"] = myString;

Microsoft.Extensions.Caching.Memory
This one is tightly coupled with Dependency Injection. This is one way to implement it:

// In asp.net core's Startup add this:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
}

Using it on a controller:

// Add a using
using Microsoft.Extensions.Caching.Memory;

// In your controller's constructor, you add the dependency on the 'IMemoryCache'
public class HomeController : Controller
{
    private IMemoryCache _cache;
    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

    public void Test()
    {
        // To get a value
        string myString = null;
        if (_cache.TryGetValue("itemCacheKey", out myString))
        { /*  key/value found  -  myString has the key cache's value*/  }


        // To store a value
        _cache.Set("itemCacheKey", myString);
    }
}

As pointed by @WillC, this answer is actually a digest of Cache in-memory in ASP.NET Core documentation. You can find extended information there.

like image 27
Vitox Avatar answered Oct 23 '22 10:10

Vitox


  • Inject MemoryCache Through constructor (get the reference from nugget Microsoft.Extensions.Caching.Memory)
 private readonly IMemoryCache memoryCache;
  • Code Implementation
 private IList<Employee> GetListFromCache()
        {
            const string Key = "employee";
            IList<Employee> cacheValue = null;
            if (!this.memoryCache.TryGetValue(Key, out cacheValue))
            {
                //// Key not in cache, so get data.
                cacheValue = this.context.Employee.AsNoTracking().Include(x => 
                x.Id).ToList();
                       
                //// Set cache options.
                var cacheEntryOptions = new MemoryCacheEntryOptions()
                    //// Keep in cache for this time, reset time if accessed.
                    .SetSlidingExpiration(TimeSpan.FromDays(1));

                //// Save data in cache.
                this.memoryCache.Set(Key, cacheValue, cacheEntryOptions);
            }

            return cacheValue;
        }

Register AddMemoryCache under ConfigureServices in Startup.cs

 services.AddMemoryCache();
  • Mock IMemoryCache for Unit Test
     /// <summary>Gets the memory cache.</summary>
        /// <returns> Memory cache object.</returns>
        public IMemoryCache GetMemoryCache()
        {
            var services = new ServiceCollection();
            services.AddMemoryCache();
            var serviceProvider = services.BuildServiceProvider();

            return serviceProvider.GetService<IMemoryCache>();
        }

//Inject memory cache in constructor for unit test
  this.memoryCache = text.GetMemoryCache();
like image 5
Dev-lop-er Avatar answered Oct 23 '22 08:10

Dev-lop-er


If you using Asp.net core you no need to custom SingleTon for cache, because Asp.net core is supported DI for your Cache class.

To using IMemoryCache to set data to the memory of the server you can do as below:

public void Add<T>(T o, string key)
{
    if (IsEnableCache)
    {
        T cacheEntry;

        // Look for cache key.
        if (!_cache.TryGetValue(key, out cacheEntry))
        {
            // Key not in cache, so get data.
            cacheEntry = o;

            // Set cache options.
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                // Keep in cache for this time, reset time if accessed.
                .SetSlidingExpiration(TimeSpan.FromSeconds(7200));

            // Save data in cache.
            _cache.Set(key, cacheEntry, cacheEntryOptions);
        }
    }
}
like image 1
Dung Do Tien Avatar answered Oct 23 '22 08:10

Dung Do Tien