Question

I have implemented a very simple object cache in C# using AppDomain SetData() and GetData() like this (to reduce the number of DB calls for data that changes infrequently):

class Program
{
    static void Main(string[] args)
    {
        List<string> users = (List<string>)GetUserList();

        Console.ReadKey();
    }

    private static object GetUserList()
    {
        var users = AppDomain.CurrentDomain.GetData("GetUserList");

        if (null == users)
        {
            users = new List<string>() { "apple", "banana" }; // dummy db results
            AppDomain.CurrentDomain.SetData("GetUserList", users); 
        }

        return users;
    }
}

I now want to implement a simple PurgeCache() method iterate through the keys in my CurrentDomain and set the value to null.

How can I go about doing this?


EDIT

Based on Knaģis's reply, I have come up with the following.

ObjectCache.cs

class ObjectCache
{
    private const string CacheName = "ObjectCache";

    private static Dictionary<String, Object> Load()
    {
        Dictionary<string, object> myObjectCache = AppDomain.CurrentDomain.GetData(CacheName) as Dictionary<string, object>;
        if (null == myObjectCache)
        {
            myObjectCache = new Dictionary<string, object>();
            AppDomain.CurrentDomain.SetData(CacheName, myObjectCache);
        }
        return myObjectCache;
    }

    private static void Save(Object myObjectCache)
    {
        AppDomain.CurrentDomain.SetData(CacheName, myObjectCache);
    }

    public static void Purge()
    {
        Dictionary<string, object> myObjectCache = ObjectCache.Load();
        myObjectCache.Clear();
        ObjectCache.Save(myObjectCache);
    }

    public static void SetValue(String myKey, Object myValue)
    {
        Dictionary<string, object> myObjectCache = ObjectCache.Load();
        myObjectCache[myKey] = myValue;
        ObjectCache.Save(myObjectCache);
    }

    public static Object GetValue(String myKey)
    {
        Dictionary<string, object> myObjectCache = ObjectCache.Load();
        return myObjectCache.ContainsKey(myKey) ? myObjectCache[myKey] : null;
    }
}

Program.cs - Usage

class Program
{
    static void Main(string[] args)
    {
        List<string> users = GetUserList<List<string>>();

        ObjectCache.Purge(); // Removes Cache

        Console.ReadKey();
    }

    private static T GetUserList<T>()
    {
        var users = ObjectCache.GetValue("GetUserList");

        if (null == users) // No Cache
        {
            users = new List<string>() { "adam", "smith" }; // Dummy DB Results
            ObjectCache.SetValue("GetUserList", users);
        }

        return (T)users;
    }
}
Was it helpful?

Solution

AppDomain.GetData should not be used for caching purposes. Instead use solutions like System.Runtime.Caching. Or even just a static ConcurrentDictionary will be better.

If you insist on using AppDomain to store the values you should never delete everything in it - it stores information required by .NET framework to run properly.

Either store your values in a dictionary inside the AppDomain object or keep a list of keys yourself.

A simple in memory cache using a static dictionary (the second approach is for .NET 2.0 with explicit locks - note that this is very simple solution, there are better alternatives to locking):

using System;
using System.Collections.Concurrent;

namespace YourNamespace
{
    public static class ObjectCache
    {
        private readonly static ConcurrentDictionary<string, object> Data = new ConcurrentDictionary<string, object>();

        public static void SetValue(string key, object value)
        {
            Data[key] = value;
        }

        public static object GetValue(string key)
        {
            object t;
            if (!Data.TryGetValue(key, out t))
                return null;
            return t;
        }

        public static void Purge()
        {
            Data.Clear();
        }
    }

    public static class ObjectCache2
    {
        private readonly static Dictionary<string, object> Data = new Dictionary<string, object>();

        public static void SetValue(string key, object value)
        {
            lock (Data)
                Data[key] = value;
        }

        public static object GetValue(string key)
        {
            object t;
            lock (Data)
            {
                if (!Data.TryGetValue(key, out t))
                    return null;
            }
            return t;
        }

        public static void Purge()
        {
            lock (Data)
                Data.Clear();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top