2

我正在尝试实现基于 ObjectCache 的FileCache ( https://github.com/acarteas/FileCache )。我正在尝试检查缓存对象是否存在,或者在需要时添加它并返回。但是,当对象不存在时,不会执行委托并引发错误: [...] 中的类型“myNamespace.Controllers.ListController+<>c__DisplayClass0_0”未标记为可序列化。

我尝试过的(简化):

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);

}

好的,现在我尝试使用 Serializable 指定委托 createString,但这不起作用。有人能指出我正确的方向吗?

本质上我想要: - 运行一个返回 generateString(123) 的先前输出的语句;如果它不存在或过期,它应该重新生成它。

感谢您的任何提示!

4

2 回答 2

2

由于 的性质FileCache,我认为唯一合理的方法是回退到通常的方式 - 检查项目是否存在于缓存中,如果不存在 - 添加它:

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) });
    }
}

锁定是必要的,因为FileCache从同一个文件中写入和读取,并且从多个线程执行此操作永远不会安全。

于 2018-04-30T20:33:44.790 回答
1

签名AddOrGetExisting表示第二个参数是object value而不是回调委托:

https://github.com/acarteas/FileCache/blob/master/src/FileCache/FileCache.cs

public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)

我想你只是想要这个(我也纠正了你代码中的其他潜在问题):

public ActionResult GetSomething(int? id)
{
    String cacheFilePath = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "Cache" );
    FileCache cache = new FileCache( cacheFilePath, false, TimeSpan.FromSeconds(30) );

    String cacheKey = String.Format( CultureInfo.InvariantCulture, "CacheKey{0}", id );
    if( purgeCache ) cache.Remove( cacheKey );

    String valueString = this.GenerateString( id );

    String myString = (String)cache.AddOrGetExisting( cacheKey, valueString, new CacheItemPolicy() { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30) });
    return new JsonStringResult( myString );

}
  1. C# 插值字符串$"like {this}"不适合在 UI 代码之外使用,因为它们会自动使用CultureInfo.CurrentCulture,这会导致输出不一致,具体取决于当前线程的文化,在 ASP.NET 中自动将其设置为访问者浏览器的Accept-Language标头值。最好改用显式String.Format( CultureInfo.InvariantCulture, format, args )
  2. 您的代码具有用于生成缓存键的冗余步骤,我将其移至单个变量cacheKey
  3. C# 命名约定camelCase用于参数和局部变量以及PascalCase方法。
于 2018-04-30T19:46:30.380 回答