Cached item returned from MemoryCache seems to mutate MemoryCache instance when modified. #145
-
Just started to see this occur and can't figure out for the life of me how. .Net 7 Normal cache call: Public Task<List<string>> MyMethod {
List<string> myListOfThings = await _cache.GetOrSetAsync(key, _ => asyncFunction, options => options.SetDuration(TimeSpan.FromMinutes(5)))
if (myListOfThings[1] != "Changed Value")
myListOfThings[1] = "Changed Value";
)
return myListOfThings;
} Next call of this method, myListOfThings[1] already == "ChangeValue" after being retrieved from the cache. Debug logging shows a cache hit in Memory. builder.Services.AddMemoryCache();
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ##ConnectionString##;
});
builder.Services.AddFusionCache()
.WithOptions(opts =>
{
opts.FailSafeActivationLogLevel = LogLevel.Debug;
opts.SerializationErrorsLogLevel = LogLevel.Warning;
opts.DistributedCacheSyntheticTimeoutsLogLevel = LogLevel.Debug;
opts.DistributedCacheErrorsLogLevel = LogLevel.Error;
opts.FactorySyntheticTimeoutsLogLevel = LogLevel.Debug;
opts.FactoryErrorsLogLevel = LogLevel.Error;
})
.WithDefaultEntryOptions(opts =>
{
opts.Duration = TimeSpan.FromMinutes(2);
})
.WithSystemTextJsonSerializer(new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles
})
.WithRegisteredDistributedCache()
.WithStackExchangeRedisBackplane(opts =>
{
opts.Configuration = ##ConnectionString##;
}) Is this expected behavior? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
Hi @rlightner and thanks for using FusionCache! Yes, you are right: in general what you get from a cache is a reference of the data there (if we are talking about a reference type, like in this case). More specifically, FusionCache uses
Exactly: the first call populate the cache with an instance of Hope this helps! |
Beta Was this translation helpful? Give feedback.
The only solution is to do some sort of "deep clone", in theory.
But if you try to do that you'll see pretty quickly that there are a lot of "ifs" (serializability and friends) and "buts" (cycles) and in general various things to consider, including - but not limited to - performance considerations.
Because of this, it is not something that in general is done natively inside of caching solutions, including FusionCache.
I would suggest you to consider objects received from the cache not to be modifiable, and clone them yourselves only if and when needed.
You can find various solutions online on how to do deep clones in C# (with various limitations and perf considerations).
Let me know if t…