Menu

Asp.net Cache Core – using in memory cache

Most of the apps we write have some data that not get updated frequently or not get updated at all. For example – suburb list, user roles, etc. We can avoid reading the database for all those entities by using a cached collection. if you do have to update the cache you can by using a cache.Remove(‘key’); below is the implementation I used for one of my entities (of course you can write fancier code:) )

public interface IOutletCacheService
{
  void Clear();
  Task<IEnumerable<Outlet>> GetOutlets();
}

Here is the simple implementation.

    public class OutletCacheService : IOutletCacheService
    {
        private const string outletCacheKey = "outlet-cache-key-ha-ha-ha";

        private readonly IMemoryCache _cache;
        private readonly MybContext _db;

        public TradingOutletCacheService(IMemoryCache cache, MybContext db)
        {
            _cache = cache;
            _db = db;
        }

        public void Clear()
        {
            _cache.Remove(outletCacheKey);
        }

        public async Task<IEnumerable<TradingOutlet>> GetOutlets()
        {
            if (_cache.TryGetValue(outletCacheKey , out IEnumerable<Outlet> outlets))
            {
                return outlets;
            }

            outlets = await _db.Outlets.Where(o => o.Active == true).ToListAsync();

            _cache.Set(outletCacheKey, outlets);

            return outlets;
        }
    }

Easy ?

Now in the Startup.cs, maybe you can register it as a Singleton? I have not tested it out yet.

public void ConfigureServices(IServiceCollection services)
{
  services.AddMediatR();

  ......
          
  services.AddMvc();

  services.AddMemoryCache();

  services.AddAutoMapper(GetType().Assembly);

  services.AddScoped<IPasswordHasher, PasswordHasher>();
  services.AddScoped<IJwtTokenGenerator, JwtTokenGenerator>();
  services.AddScoped<ICurrentUserAccessor, CurrentUserAccessor>();
  services.AddScoped<IOutletCacheService, OutletCacheService>();
  ......
  ......

  services.AddJwt();
}

Whenever I need to refresh it I call _cacheService.Clear(), like below.

 public class Update
    {
        public class Handler : IRequestHandler<UpdateCommand, OutletEnvelope>
        {
            private readonly MyContext _db;
            private readonly IOutletCacheService _cacheService;

            public Handler(MyContext db, IOutletCacheService cacheService)
            {
                _db = db;
                _cacheService = cacheService;
            }

            public async Task<OutletEnvelope> Handle(UpdateCommand message, CancellationToken cancellationToken)
            {
                var entity = await _db.Outlets
                    .Where(o => o.OutletId == message.OutletId)
                    .SingleOrDefaultAsync(cancellationToken);

                if (entity == null)
                    throw new RestException(HttpStatusCode.NotFound);

                Mapper.Map(message, entity);

                await _db.SaveChangesAsync(cancellationToken);

                _cacheService.Clear();

                return new OutletEnvelope(entity);
            }
        }

Happy coding

Leave a comment