2018-11-22 14:05:51 +00:00
using System ;
2015-05-18 16:03:25 +10:00
using System.Collections.Generic ;
using System.Linq ;
using System.Web.Caching ;
using Umbraco.Core.Models ;
2018-11-22 14:05:51 +00:00
using Umbraco.Core.Models.EntityBase ;
2015-05-18 16:03:25 +10:00
2016-01-06 14:17:51 +01:00
namespace Umbraco.Core.Cache
2015-05-18 16:03:25 +10:00
{
2016-02-04 11:01:54 +01:00
/// <summary>
/// Interface describing this cache provider as a wrapper for another
/// </summary>
internal interface IRuntimeCacheProviderWrapper
{
IRuntimeCacheProvider InnerProvider { get ; }
}
2015-05-18 16:03:25 +10:00
/// <summary>
2018-11-22 14:05:51 +00:00
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
2015-05-21 17:04:14 +10:00
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
/// reset if the object is TracksChangesEntityBase
2015-05-18 16:03:25 +10:00
/// </summary>
2016-02-04 11:01:54 +01:00
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider , IRuntimeCacheProviderWrapper
2015-05-18 16:03:25 +10:00
{
2018-11-22 14:05:51 +00:00
public IRuntimeCacheProvider InnerProvider { get ; private set ; }
2015-05-18 16:03:25 +10:00
public DeepCloneRuntimeCacheProvider ( IRuntimeCacheProvider innerProvider )
{
2018-11-22 14:05:51 +00:00
if ( innerProvider . GetType () == typeof ( DeepCloneRuntimeCacheProvider ))
throw new InvalidOperationException ( "A " + typeof ( DeepCloneRuntimeCacheProvider ) + " cannot wrap another instance of " + typeof ( DeepCloneRuntimeCacheProvider ));
2017-05-12 14:49:44 +02:00
2015-05-21 17:04:14 +10:00
InnerProvider = innerProvider ;
2015-05-18 16:03:25 +10:00
}
#region Clear - doesn ' t require any changes
public void ClearAllCache ()
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearAllCache ();
2015-05-18 16:03:25 +10:00
}
public void ClearCacheItem ( string key )
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheItem ( key );
2015-05-18 16:03:25 +10:00
}
public void ClearCacheObjectTypes ( string typeName )
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheObjectTypes ( typeName );
2015-05-18 16:03:25 +10:00
}
public void ClearCacheObjectTypes < T >()
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheObjectTypes < T >();
2015-05-18 16:03:25 +10:00
}
public void ClearCacheObjectTypes < T >( Func < string , T , bool > predicate )
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheObjectTypes < T >( predicate );
2015-05-18 16:03:25 +10:00
}
public void ClearCacheByKeySearch ( string keyStartsWith )
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheByKeySearch ( keyStartsWith );
2015-05-18 16:03:25 +10:00
}
public void ClearCacheByKeyExpression ( string regexString )
{
2015-05-21 17:04:14 +10:00
InnerProvider . ClearCacheByKeyExpression ( regexString );
2018-11-22 14:05:51 +00:00
}
2015-05-18 16:03:25 +10:00
#endregion
public IEnumerable < object > GetCacheItemsByKeySearch ( string keyStartsWith )
{
2015-05-21 17:04:14 +10:00
return InnerProvider . GetCacheItemsByKeySearch ( keyStartsWith )
2015-05-18 16:03:25 +10:00
. Select ( CheckCloneableAndTracksChanges );
}
public IEnumerable < object > GetCacheItemsByKeyExpression ( string regexString )
{
2015-05-21 17:04:14 +10:00
return InnerProvider . GetCacheItemsByKeyExpression ( regexString )
2015-05-18 16:03:25 +10:00
. Select ( CheckCloneableAndTracksChanges );
}
2018-11-22 14:05:51 +00:00
2015-05-18 16:03:25 +10:00
public object GetCacheItem ( string cacheKey )
{
2015-05-21 17:04:14 +10:00
var item = InnerProvider . GetCacheItem ( cacheKey );
2015-05-18 16:03:25 +10:00
return CheckCloneableAndTracksChanges ( item );
}
public object GetCacheItem ( string cacheKey , Func < object > getCacheItem )
{
2015-09-07 12:38:46 +02:00
var cached = InnerProvider . GetCacheItem ( cacheKey , () =>
2015-05-18 16:03:25 +10:00
{
2015-05-21 17:04:14 +10:00
var result = DictionaryCacheProviderBase . GetSafeLazy ( getCacheItem );
var value = result . Value ; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if ( value == null ) return null ; // do not store null values (backward compat)
return CheckCloneableAndTracksChanges ( value );
2015-05-18 16:03:25 +10:00
});
2015-09-07 12:38:46 +02:00
return CheckCloneableAndTracksChanges ( cached );
2015-05-18 16:03:25 +10:00
}
public object GetCacheItem ( string cacheKey , Func < object > getCacheItem , TimeSpan ? timeout , bool isSliding = false , CacheItemPriority priority = CacheItemPriority . Normal , CacheItemRemovedCallback removedCallback = null , string [] dependentFiles = null )
{
2015-09-07 12:38:46 +02:00
var cached = InnerProvider . GetCacheItem ( cacheKey , () =>
2015-05-18 16:03:25 +10:00
{
2015-05-21 17:04:14 +10:00
var result = DictionaryCacheProviderBase . GetSafeLazy ( getCacheItem );
var value = result . Value ; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if ( value == null ) return null ; // do not store null values (backward compat)
2018-11-22 14:05:51 +00:00
//Clone/reset to go into the cache
2015-05-21 17:04:14 +10:00
return CheckCloneableAndTracksChanges ( value );
2015-09-07 12:38:46 +02:00
}, timeout , isSliding , priority , removedCallback , dependentFiles );
2018-11-22 14:05:51 +00:00
//Clone/reset to go out of the cache
2015-09-07 12:38:46 +02:00
return CheckCloneableAndTracksChanges ( cached );
2015-05-18 16:03:25 +10:00
}
public void InsertCacheItem ( string cacheKey , Func < object > getCacheItem , TimeSpan ? timeout = null , bool isSliding = false , CacheItemPriority priority = CacheItemPriority . Normal , CacheItemRemovedCallback removedCallback = null , string [] dependentFiles = null )
{
2015-05-21 17:04:14 +10:00
InnerProvider . InsertCacheItem ( cacheKey , () =>
2015-05-18 16:03:25 +10:00
{
2015-05-21 17:04:14 +10:00
var result = DictionaryCacheProviderBase . GetSafeLazy ( getCacheItem );
var value = result . Value ; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if ( value == null ) return null ; // do not store null values (backward compat)
return CheckCloneableAndTracksChanges ( value );
2018-11-22 14:05:51 +00:00
}, timeout , isSliding , priority , removedCallback , dependentFiles );
2015-05-18 16:03:25 +10:00
}
private static object CheckCloneableAndTracksChanges ( object input )
{
2015-05-21 17:04:14 +10:00
var cloneable = input as IDeepCloneable ;
if ( cloneable != null )
{
2018-11-22 14:05:51 +00:00
input = cloneable . DeepClone ();
2015-05-21 17:04:14 +10:00
}
2015-05-18 16:03:25 +10:00
2018-11-22 14:05:51 +00:00
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
2015-05-21 17:04:14 +10:00
var tracksChanges = input as IRememberBeingDirty ;
2015-05-18 16:03:25 +10:00
if ( tracksChanges != null )
{
tracksChanges . ResetDirtyProperties ( false );
2015-05-21 17:04:14 +10:00
input = tracksChanges ;
2015-05-18 16:03:25 +10:00
}
2015-05-21 17:04:14 +10:00
return input ;
2015-05-18 16:03:25 +10:00
}
}
2018-11-22 14:05:51 +00:00
}