Search code examples
c#.netasp.net-corememorycache

How to store nested lists of objects using MemoryCache in dotnet


I'm trying to find the best way to store complex objects in a MemoryCache (specifically Microsoft.Extensions.Caching.Memory.MemoryCache).

My data's structure would be something as below:

public class Foo
{
    public Guid Id { get; set; }
    public IList<Bar> Bars { get; set; }
}

public class Bar
{
   public Guid Id { get; set; }
   public Guid ParentFooId { get; set; }
}

From an API call, I get some Foo instance with some Bars inside. It will be registered to a MemoryCache instance using:

CacheInstance = new MemoryCache();

CacheInstance.Set(fooInstance.Id, fooInstance);

//At some later point:
var cached = CacheInstance.Get<Foo>(foo.Id);

After this call, cached will be Foo, but cached.Bars will be empty.

Is there any way to store Foo an then retrieve it keeping the Bars inside?

[EDIT - SOLVED]

With the hints on the comments and the kind working example, I was able to track the issue.

There was another class Zee at some other point in the application.

As you might be imagining, it looks like:

public Class Zee
{
    public Guid Id { get; set; }
    public IList<Guid> FooIds { get; set }
}

When an instance of Zee was being cached, it was also running the FooIds and retrieving them from the API, but with an endpoint that would not include Bars.

As one might expect, the Foos present in cache where being overwritten by these incomplete versions.

Since all this procedure was going on with async calls, it was a little though to pinpoint "who" was overwriting.

Again, thank you very much for clearing my doubt about the MemoryCache mechanics and pointing me in the right direction!


Solution

  • As I expected the Cache works (or I cant make it fail as you describe it), must be bug somewhere in your code. This is out of the box .NET 6 asp.net core app:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.Extensions.Caching.Memory;
    using System.Diagnostics;
    
    namespace WebApplication2.Pages
    {
        public class Foo
        {
            public Guid Id { get; set; }
            public IList<Bar> Bars { get; set; }
        }
    
        public class Bar
        {
            public Guid Id { get; set; }
            public Guid ParentFooId { get; set; }
        }
    
        public class IndexModel : PageModel
        {
            private readonly ILogger<IndexModel> _logger;
    
            Guid fooid;
            Foo foo;
            MemoryCache CacheInstance;
    
            public IndexModel(ILogger<IndexModel> logger)
            {
                _logger = logger;
    
                fooid = Guid.NewGuid();
                foo = new Foo()
                {
                    Id = fooid,
                    Bars = new List<Bar>()
                    {
                        new Bar() { Id = Guid.NewGuid(), ParentFooId = fooid },
                        new Bar() { Id = Guid.NewGuid(), ParentFooId = fooid },
                    }
                };
    
                var opts = new MemoryCacheOptions() { CompactionPercentage = 0.50 };
                CacheInstance = new MemoryCache(opts);
    
                CacheInstance.Set(fooid, foo);
    
            }
    
            public ActionResult OnPostButtonClick(string data)
            {
                var cached = CacheInstance.Get<Foo>(fooid);
                var response = string.Format("Check Cache: foo: ({0}) bar: ({1})", cached == null ? "NULL" : "NOT NULL", cached?.Bars == null ? "NULL" : "NOT NULL");
    
                return new JsonResult("Cache Checked: " + response + " at " + DateTime.Now);
            }
    
            public void OnGet()
            {
    
            }
        }
    }