Search code examples
c#objectcache

Func<string> DoSomething: Type [...] Controller+<>c__DisplayClass0_0 is not marked as serializable


I'm trying to implement FileCache (https://github.com/acarteas/FileCache) which is based on ObjectCache. I'm trying to check a cache object for its existence, or add it if required and return. When the object does not exist however, the delegate is not executed and an error is thrown: Type 'myNamespace.Controllers.ListController+<>c__DisplayClass0_0' in [...] is not marked as serializable.

What I've tried (simplified):

private string generateString(int? Id)
{ 
    return "String";
}

public ActionResult GetSomething(int? Id)
{
    var cacheFilePath = $"{AppDomain.CurrentDomain.BaseDirectory}{"\\cache"}";
    var cache = new FileCache(cacheFilePath, false, TimeSpan.FromSeconds(30));
    if (purgeCache)
        cache.Remove($"CacheKey{Id}");

    Func<string> createString = () => generateString(Id);

    var myString = (string) cache.AddOrGetExisting($"CacheKey{Id}", createString, new CacheItemPolicy() { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30) });
    return new JsonStringResult(myString);

}

Ok, now I've tried to specify the delegate createString with Serializable, but that doesn't work. Could someone point me into the right direction?

Essentially I want: - run a statement that returns a previous output of generateString(123); if it doesn't exist or is expired, it should re-generate it.

Thanks for any tips!


Solution

  • Due to the nature of FileCache, I think the only reasonable way to do that is to fallback to the usual way - check if item exists in cache and if not - add it:

    private static readonly _cacheLock = new object();
    private static readonly FileCache _cache = new FileCache($"{AppDomain.CurrentDomain.BaseDirectory}{"\\cache"}", false, TimeSpan.FromSeconds(30));
    /// ...
    lock (_cacheLock) {
        var myString = _cache.Get($"CacheKey{Id}");
        if (myString == null) {
            myString = generateString(Id);
            _cache.Set($"CacheKey{Id}", myString, new CacheItemPolicy() { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30) });
        }
    }
    

    Lock is necessary because FileCache both writes and reads from the same file, and this is never safe to do from multiple threads.