1

I have a ASP.Net MVC project running on .NET 4.6.1 Framework. I have recently added Unity.Mvc 5 IoC framework for dependency injection

In order to have flexibility for unit testing and other, I moved my Unity Configuration to a separate class library so that I can call the Unity Register methods from Unit test projects and other as needed.

Here is my high-level solution design.

I would like to use the same class library to implement application cache.

When I installed Unity.Mvc5 from nuget package it added following references (I added some of them manually) :

  • Microsoft.Practices.EnterpriseLibrary.Caching 5.0.505.0
  • Enterprise Library Shared Library 5.0.505.0
  • Microsoft.Practices.ServiceLocation 1.3.0.0
  • Microsoft.Practices.Unity 4.0.0.0
  • Microsoft.Practices.Unity.Configuration 4.0.0.0
  • Microsoft.Practices.Unity.Interception 2.1.505.0
  • Microsoft.Practices.Unity.Interception.Configuration 2.1.505.0
  • Microsoft.Practices.Unity.RegistrationByConvention 4.0.0.0

I tried few articles to implement Application Block Cache Management so that I can cache data in my Service Implementer layers, but all those documentations are showing code examples which is expecting Unity 2.xxx version.

Here is my Unity Configuration

 public static class UnityConfig
    {
        public static void RegisterComponents()
        {
            var container = new UnityContainer();
            container.RegisterType<UserManager<User>>(new HierarchicalLifetimeManager());
            container.RegisterType<IUserStore<User>, UserStore<User>>(new HierarchicalLifetimeManager());
            container.RegisterType<DbContext, OfficeGxDbContext>(new HierarchicalLifetimeManager());
            container.RegisterType<IAppSetting, AppSettingService>();
            container.RegisterType<ISubscription, SubscriptionService>();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
    }

In my AppSettingService.cs I have get all method

public List<AppSetting> All()
        {
            using (var context = new MyDbContext())
            {
                //CachecKeyItem.AppSettingsAll
                return context.AppSettings.Where(x => !x.IsDeleted)
                    .Include(x => x.Module).ToList();
            }
        }

I want to store this data in cache and reuse it. Similarly do this across all projects I have in my solution and if there is any update or add or delete for any DB records, I want the cached object to refresh it so that cached object is always in sync with DB data

I ended up doing something like this

public interface ICacheService
    {
        T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
    }

Service Implementor

 public class InMemoryCache : ICacheService
    {
        public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
        {
            if (MemoryCache.Default.Get(cacheKey) is T item) return item;
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(8));
            return item;
        }
    }

use like this

_cacheService.GetOrSet(CachecKeyItem.AppSettingsAll, () => context.AppSettings
                    .Where(x => !x.IsDeleted)
                    .Include(x => x.Module).ToList());

Now my question is, when there is any change to data, like add/edit/delete, how do I refresh the cache in most efficient way? I know deleting the key would be one, is there a better way?

HaBo
  • 13,999
  • 36
  • 114
  • 206

1 Answers1

0

It slightly depends on if your running in a single server system or multi server system. Its generally better to always design for multi-server that way if you ever decide to scale out your already sorted.

So assuming you can get a message to fire off when your cache invalidates to all the servers without issue then the easiest way is to delete your cache key... now that also brings a few areas of optimization that can be looked at.

Is this cached data utilized heavily, in which case may you benefit from a pre-fetch cache where you either send the updated cached entry to all servers or require all servers to ask for it? Is it used very little in which case you don't really want to re-populate until its requested otherwise your needlessly bloating your application.

John Mitchell
  • 9,653
  • 9
  • 57
  • 91
  • So what is the best way to delete the cache Key as there is a update to data? – HaBo Nov 05 '17 at 09:30
  • That depends if you want to pre-fetch, one way would be to UPDATE the cache key instead with the latest values. Or you could just delete the key from the cache.Remove(key); See https://msdn.microsoft.com/en-us/library/ff664524(v=pandp.50).aspx – John Mitchell Nov 05 '17 at 20:17
  • Also if the cached values that change invalidate the entire cache (i.e a tax rate and ALL products use that tax rate, then you can flush the entire cache using the cache.Flush() ) command. – John Mitchell Nov 05 '17 at 20:22