Func <string>DoSomething: Type [...] Controller + <> c__DisplayClass0_0 не помечен как сериализуемый - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь реализовать FileCache (https://github.com/acarteas/FileCache), который основан на ObjectCache. Я пытаюсь проверить объект кэша на наличие или добавить его, если требуется, и вернуть. Однако, когда объект не существует, делегат не выполняется и выдается ошибка: Тип '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);

}

Хорошо, теперь я попытался указать делегат createString с Serializable, но это не работает. Может ли кто-нибудь указать мне правильное направление?

По сути, я хочу: - запустить оператор, который возвращает предыдущий вывод generateString (123); если он не существует или срок его действия истек, он должен сгенерировать его заново.

Спасибо за любые советы!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Из-за природы 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 записывает и читает из одного и того же файла, и это никогда не безопасно делать из нескольких потоков.

0 голосов
/ 30 апреля 2018

Подпись для 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}" не подходят для использования вне кода пользовательского интерфейса, потому что они автоматически используют CultureInfo.CurrentCulture, что приводит к несогласованным выводам в зависимости от культуры текущего потока, которая в ASP.NET автоматически устанавливается на * 1015 в браузере посетителя. * значение заголовка. Вместо этого лучше использовать экспликт String.Format( CultureInfo.InvariantCulture, format, args ).
  2. В вашем коде были избыточные шаги для генерации ключа кеша, вместо этого я переместил его в одну переменную cacheKey.
  3. Соглашения об именах C # используют camelCase для параметров и локальных параметров и PascalCase для методов.
...