diff --git a/src/Umbraco.Core/Cache/CacheProviderBase.cs b/src/Umbraco.Core/Cache/CacheProviderBase.cs
index fafa0939f8..026f6f9dbc 100644
--- a/src/Umbraco.Core/Cache/CacheProviderBase.cs
+++ b/src/Umbraco.Core/Cache/CacheProviderBase.cs
@@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Text;
-using System.Web.Caching;
namespace Umbraco.Core.Cache
{
///
- /// An abstract class for implementing a cache helper
+ /// An abstract class for implementing a basic cache provider
///
///
/// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC...
@@ -22,13 +20,5 @@ namespace Umbraco.Core.Cache
public abstract IEnumerable GetCacheItemsByKeySearch(string keyStartsWith);
public abstract T GetCacheItem(string cacheKey);
public abstract T GetCacheItem(string cacheKey, Func getCacheItem);
- public abstract T GetCacheItem(string cacheKey, TimeSpan? timeout, Func getCacheItem);
- public abstract T GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem);
- public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem);
- public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
- public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem);
- public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func getCacheItem);
- public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
- public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
}
-}
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
index 681dc8fab4..e574f38454 100644
--- a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Cache
///
/// A CacheProvider that wraps the logic of the HttpRuntime.Cache
///
- internal class HttpRuntimeCacheProvider : CacheProviderBase
+ internal class HttpRuntimeCacheProvider : RuntimeCacheProviderBase
{
private readonly System.Web.Caching.Cache _cache;
private static readonly object Locker = new object();
diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs
index 3a41ae2a77..3d1bbaa79d 100644
--- a/src/Umbraco.Core/Cache/NullCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/NullCacheProvider.cs
@@ -5,7 +5,7 @@ using System.Web.Caching;
namespace Umbraco.Core.Cache
{
- internal class NullCacheProvider : CacheProviderBase
+ internal class NullCacheProvider : RuntimeCacheProviderBase
{
public override void ClearAllCache()
{
diff --git a/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs
new file mode 100644
index 0000000000..9dddb4c576
--- /dev/null
+++ b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Text;
+using System.Web.Caching;
+
+namespace Umbraco.Core.Cache
+{
+ ///
+ /// An abstract class for implementing a runtime cache provider
+ ///
+ ///
+ /// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC...
+ ///
+ internal abstract class RuntimeCacheProviderBase : CacheProviderBase
+ {
+ public abstract T GetCacheItem(string cacheKey, TimeSpan? timeout, Func getCacheItem);
+ public abstract T GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem);
+ public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem);
+ public abstract T GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
+ public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem);
+ public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func getCacheItem);
+ public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
+ public abstract void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem);
+ }
+}
diff --git a/src/Umbraco.Core/Cache/StaticCacheProvider.cs b/src/Umbraco.Core/Cache/StaticCacheProvider.cs
new file mode 100644
index 0000000000..0d0d2f288c
--- /dev/null
+++ b/src/Umbraco.Core/Cache/StaticCacheProvider.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Web.Caching;
+
+namespace Umbraco.Core.Cache
+{
+ ///
+ /// A cache provider that statically caches everything in an in memory dictionary
+ ///
+ internal class StaticCacheProvider : CacheProviderBase
+ {
+ private readonly ConcurrentDictionary _staticCache = new ConcurrentDictionary();
+
+ public override void ClearAllCache()
+ {
+ _staticCache.Clear();
+ }
+
+ public override void ClearCacheItem(string key)
+ {
+ object val;
+ _staticCache.TryRemove(key, out val);
+ }
+
+ public override void ClearCacheObjectTypes(string typeName)
+ {
+ foreach (var key in _staticCache.Keys)
+ {
+ if (_staticCache[key] != null
+ && _staticCache[key].GetType().ToString().InvariantEquals(typeName))
+ {
+ object val;
+ _staticCache.TryRemove(key, out val);
+ }
+ }
+ }
+
+ public override void ClearCacheObjectTypes()
+ {
+ foreach (var key in _staticCache.Keys)
+ {
+ if (_staticCache[key] != null
+ && _staticCache[key].GetType() == typeof(T))
+ {
+ object val;
+ _staticCache.TryRemove(key, out val);
+ }
+ }
+ }
+
+ public override void ClearCacheByKeySearch(string keyStartsWith)
+ {
+ foreach (var key in _staticCache.Keys)
+ {
+ if (key.InvariantStartsWith(keyStartsWith))
+ {
+ ClearCacheItem(key);
+ }
+ }
+ }
+
+ public override void ClearCacheByKeyExpression(string regexString)
+ {
+ foreach (var key in _staticCache.Keys)
+ {
+ if (Regex.IsMatch(key, regexString))
+ {
+ ClearCacheItem(key);
+ }
+ }
+ }
+
+ public override IEnumerable GetCacheItemsByKeySearch(string keyStartsWith)
+ {
+ return (from KeyValuePair c in _staticCache
+ where c.Key.InvariantStartsWith(keyStartsWith)
+ select c.Value.TryConvertTo()
+ into attempt
+ where attempt.Success
+ select attempt.Result).ToList();
+ }
+
+ public override T GetCacheItem(string cacheKey)
+ {
+ var result = _staticCache[cacheKey];
+ if (result == null)
+ {
+ return default(T);
+ }
+ return result.TryConvertTo().Result;
+ }
+
+ public override T GetCacheItem(string cacheKey, Func getCacheItem)
+ {
+ return (T)_staticCache.GetOrAdd(cacheKey, getCacheItem);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs
index 7c80a1e6d3..96b3d99de9 100644
--- a/src/Umbraco.Core/CacheHelper.cs
+++ b/src/Umbraco.Core/CacheHelper.cs
@@ -15,14 +15,13 @@ namespace Umbraco.Core
///
/// Class that is exposed by the ApplicationContext for application wide caching purposes
///
- ///
- /// This class may be opened publicly at some point but needs a review of what is absoletely necessary.
- ///
- public class CacheHelper //: CacheProviderBase
+ public class CacheHelper
{
private readonly bool _enableCache;
- private readonly HttpRuntimeCacheProvider _httpCache;
- private readonly NullCacheProvider _nullCache = new NullCacheProvider();
+ private readonly CacheProviderBase _staticCache;
+ private readonly CacheProviderBase _nullStaticCache = new NullCacheProvider();
+ private readonly RuntimeCacheProviderBase _httpCache;
+ private readonly RuntimeCacheProviderBase _nullHttpCache = new NullCacheProvider();
public CacheHelper(System.Web.Caching.Cache cache)
: this(cache, true)
@@ -30,21 +29,185 @@ namespace Umbraco.Core
}
internal CacheHelper(System.Web.Caching.Cache cache, bool enableCache)
- {
- _httpCache = new HttpRuntimeCacheProvider(cache);
- _enableCache = enableCache;
+ : this(new HttpRuntimeCacheProvider(cache), enableCache)
+ {
}
-
+
+ internal CacheHelper(RuntimeCacheProviderBase httpCacheProvider, bool enableCache)
+ : this(httpCacheProvider, new StaticCacheProvider(), enableCache)
+ {
+ }
+
+ internal CacheHelper(RuntimeCacheProviderBase httpCacheProvider, CacheProviderBase staticCacheProvider, bool enableCache)
+ {
+ _httpCache = httpCacheProvider;
+ _staticCache = staticCacheProvider;
+ _enableCache = enableCache;
+ }
+
+ #region Static cache
+
+ ///
+ /// Clears the item in umbraco's static cache
+ ///
+ internal void ClearAllStaticCache()
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearAllCache();
+ }
+ else
+ {
+ _staticCache.ClearAllCache();
+ }
+ }
+
+ ///
+ /// Clears the item in umbraco's static cache with the given key
+ ///
+ /// Key
+ internal void ClearStaticCacheItem(string key)
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearCacheItem(key);
+ }
+ else
+ {
+ _staticCache.ClearCacheItem(key);
+ }
+ }
+
+ ///
+ /// Clears all objects in the static cache with the System.Type name as the
+ /// input parameter. (using [object].GetType())
+ ///
+ /// The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"
+ internal void ClearStaticCacheObjectTypes(string typeName)
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearCacheObjectTypes(typeName);
+ }
+ else
+ {
+ _staticCache.ClearCacheObjectTypes(typeName);
+ }
+ }
+
+ ///
+ /// Clears all objects in the static cache with the System.Type specified
+ ///
+ internal void ClearStaticCacheObjectTypes()
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearCacheObjectTypes();
+ }
+ else
+ {
+ _staticCache.ClearCacheObjectTypes();
+ }
+ }
+
+ ///
+ /// Clears all static cache items that starts with the key passed.
+ ///
+ /// The start of the key
+ internal void ClearStaticCacheByKeySearch(string keyStartsWith)
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearCacheByKeySearch(keyStartsWith);
+ }
+ else
+ {
+ _staticCache.ClearCacheByKeySearch(keyStartsWith);
+ }
+ }
+
+ ///
+ /// Clears all cache items that have a key that matches the regular expression
+ ///
+ ///
+ internal void ClearStaticCacheByKeyExpression(string regexString)
+ {
+ if (!_enableCache)
+ {
+ _nullStaticCache.ClearCacheByKeyExpression(regexString);
+ }
+ else
+ {
+ _staticCache.ClearCacheByKeyExpression(regexString);
+ }
+ }
+
+ internal IEnumerable GetStaticCacheItemsByKeySearch(string keyStartsWith)
+ {
+ if (!_enableCache)
+ {
+ return _nullStaticCache.GetCacheItemsByKeySearch(keyStartsWith);
+ }
+ else
+ {
+ return _staticCache.GetCacheItemsByKeySearch(keyStartsWith);
+ }
+ }
+
+ ///
+ /// Returns a static cache item by key, does not update the cache if it isn't there.
+ ///
+ ///
+ ///
+ ///
+ internal TT GetStaticCacheItem(string cacheKey)
+ {
+ if (!_enableCache)
+ {
+ return _nullStaticCache.GetCacheItem(cacheKey);
+ }
+ else
+ {
+ return _staticCache.GetCacheItem(cacheKey);
+ }
+ }
+
+ ///
+ /// Gets (and adds if necessary) an item from the static cache with all of the default parameters
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal TT GetStaticCacheItem(string cacheKey, Func getCacheItem)
+ {
+ if (!_enableCache)
+ {
+ return _nullStaticCache.GetCacheItem(cacheKey, getCacheItem);
+ }
+ else
+ {
+ return _staticCache.GetCacheItem(cacheKey, getCacheItem);
+ }
+ }
+
+ #endregion
+
+
+ #region Runtime/Http Cache
+ ///
+ /// Clears the item in umbraco's runtime cache
+ ///
public void ClearAllCache()
- {
- if (!_enableCache)
- {
- _nullCache.ClearAllCache();
- }
- else
- {
- _httpCache.ClearAllCache();
- }
+ {
+ if (!_enableCache)
+ {
+ _nullHttpCache.ClearAllCache();
+ }
+ else
+ {
+ _httpCache.ClearAllCache();
+ }
}
///
@@ -55,7 +218,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- _nullCache.ClearCacheItem(key);
+ _nullHttpCache.ClearCacheItem(key);
}
else
{
@@ -73,7 +236,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- _nullCache.ClearCacheObjectTypes(typeName);
+ _nullHttpCache.ClearCacheObjectTypes(typeName);
}
else
{
@@ -84,55 +247,55 @@ namespace Umbraco.Core
///
/// Clears all objects in the System.Web.Cache with the System.Type specified
///
- public void ClearCacheObjectTypes()
- {
+ public void ClearCacheObjectTypes()
+ {
if (!_enableCache)
{
- _nullCache.ClearCacheObjectTypes();
+ _nullHttpCache.ClearCacheObjectTypes();
}
else
{
_httpCache.ClearCacheObjectTypes();
}
- }
+ }
- ///
+ ///
/// Clears all cache items that starts with the key passed.
///
/// The start of the key
public void ClearCacheByKeySearch(string keyStartsWith)
- {
+ {
if (!_enableCache)
{
- _nullCache.ClearCacheByKeySearch(keyStartsWith);
+ _nullHttpCache.ClearCacheByKeySearch(keyStartsWith);
}
else
{
_httpCache.ClearCacheByKeySearch(keyStartsWith);
}
- }
+ }
///
/// Clears all cache items that have a key that matches the regular expression
///
///
- public void ClearCacheByKeyExpression(string regexString)
- {
+ public void ClearCacheByKeyExpression(string regexString)
+ {
if (!_enableCache)
{
- _nullCache.ClearCacheByKeyExpression(regexString);
+ _nullHttpCache.ClearCacheByKeyExpression(regexString);
}
else
{
_httpCache.ClearCacheByKeyExpression(regexString);
}
- }
+ }
public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith)
{
if (!_enableCache)
{
- return _nullCache.GetCacheItemsByKeySearch(keyStartsWith);
+ return _nullHttpCache.GetCacheItemsByKeySearch(keyStartsWith);
}
else
{
@@ -140,7 +303,7 @@ namespace Umbraco.Core
}
}
- ///
+ ///
/// Returns a cache item by key, does not update the cache if it isn't there.
///
///
@@ -150,7 +313,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey);
+ return _nullHttpCache.GetCacheItem(cacheKey);
}
else
{
@@ -169,7 +332,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem);
}
else
{
@@ -190,7 +353,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, timeout, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, timeout, getCacheItem);
}
else
{
@@ -213,7 +376,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, refreshAction, timeout, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, refreshAction, timeout, getCacheItem);
}
else
{
@@ -237,7 +400,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, priority, refreshAction, timeout, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, priority, refreshAction, timeout, getCacheItem);
}
else
{
@@ -257,15 +420,15 @@ namespace Umbraco.Core
///
///
public TT GetCacheItem(string cacheKey,
- CacheItemPriority priority,
- CacheItemRemovedCallback refreshAction,
- CacheDependency cacheDependency,
- TimeSpan timeout,
- Func getCacheItem)
+ CacheItemPriority priority,
+ CacheItemRemovedCallback refreshAction,
+ CacheDependency cacheDependency,
+ TimeSpan timeout,
+ Func getCacheItem)
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
}
else
{
@@ -289,7 +452,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- return _nullCache.GetCacheItem(cacheKey, priority, null, cacheDependency, null, getCacheItem);
+ return _nullHttpCache.GetCacheItem(cacheKey, priority, null, cacheDependency, null, getCacheItem);
}
else
{
@@ -310,14 +473,14 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- _nullCache.InsertCacheItem(cacheKey, priority, getCacheItem);
+ _nullHttpCache.InsertCacheItem(cacheKey, priority, getCacheItem);
}
else
{
_httpCache.InsertCacheItem(cacheKey, priority, getCacheItem);
}
}
-
+
///
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
///
@@ -333,7 +496,7 @@ namespace Umbraco.Core
{
if (!_enableCache)
{
- _nullCache.InsertCacheItem(cacheKey, priority, timeout, getCacheItem);
+ _nullHttpCache.InsertCacheItem(cacheKey, priority, timeout, getCacheItem);
}
else
{
@@ -341,30 +504,30 @@ namespace Umbraco.Core
}
}
- ///
- /// Inserts an item into the cache, if it already exists in the cache it will be replaced
- ///
- ///
- ///
- ///
- ///
- /// This will set an absolute expiration from now until the timeout
- ///
- public void InsertCacheItem(string cacheKey,
- CacheItemPriority priority,
- CacheDependency cacheDependency,
- TimeSpan timeout,
- Func getCacheItem)
- {
+ ///
+ /// Inserts an item into the cache, if it already exists in the cache it will be replaced
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// This will set an absolute expiration from now until the timeout
+ ///
+ public void InsertCacheItem(string cacheKey,
+ CacheItemPriority priority,
+ CacheDependency cacheDependency,
+ TimeSpan timeout,
+ Func getCacheItem)
+ {
if (!_enableCache)
{
- _nullCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem);
+ _nullHttpCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem);
}
else
{
_httpCache.InsertCacheItem(cacheKey, priority, cacheDependency, timeout, getCacheItem);
}
- }
+ }
///
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
@@ -376,22 +539,23 @@ namespace Umbraco.Core
///
/// This will set an absolute expiration from now until the timeout
///
- public void InsertCacheItem(string cacheKey,
- CacheItemPriority priority,
- CacheItemRemovedCallback refreshAction,
- CacheDependency cacheDependency,
- TimeSpan? timeout,
- Func getCacheItem)
- {
+ public void InsertCacheItem(string cacheKey,
+ CacheItemPriority priority,
+ CacheItemRemovedCallback refreshAction,
+ CacheDependency cacheDependency,
+ TimeSpan? timeout,
+ Func getCacheItem)
+ {
if (!_enableCache)
{
- _nullCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
+ _nullHttpCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
}
else
{
_httpCache.InsertCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
}
- }
+ }
+ #endregion
}
diff --git a/src/Umbraco.Core/DictionaryExtensions.cs b/src/Umbraco.Core/DictionaryExtensions.cs
index 83d89fcaba..73866f2c9b 100644
--- a/src/Umbraco.Core/DictionaryExtensions.cs
+++ b/src/Umbraco.Core/DictionaryExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
@@ -10,10 +11,60 @@ using System.Web;
namespace Umbraco.Core
{
///
- /// Extension methods for dictionary
+ /// Extension methods for dictionary & concurrentdictionary
///
internal static class DictionaryExtensions
{
+ ///
+ /// Updates an item with the specified key with the specified value
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Taken from: http://stackoverflow.com/questions/12240219/is-there-a-way-to-use-concurrentdictionary-tryupdate-with-a-lambda-expression
+ ///
+ /// If there is an item in the dictionary with the key, it will keep trying to update it until it can
+ ///
+ public static bool TryUpdate(this ConcurrentDictionary dict, TKey key, Func updateFactory)
+ {
+ TValue curValue;
+ while (dict.TryGetValue(key, out curValue))
+ {
+ if (dict.TryUpdate(key, updateFactory(curValue), curValue))
+ return true;
+ //if we're looping either the key was removed by another thread, or another thread
+ //changed the value, so we start again.
+ }
+ return false;
+ }
+
+ ///
+ /// Updates an item with the specified key with the specified value
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Taken from: http://stackoverflow.com/questions/12240219/is-there-a-way-to-use-concurrentdictionary-tryupdate-with-a-lambda-expression
+ ///
+ /// WARNING: If the value changes after we've retreived it, then the item will not be updated
+ ///
+ public static bool TryUpdateOptimisitic(this ConcurrentDictionary dict, TKey key, Func updateFactory)
+ {
+ TValue curValue;
+ if (!dict.TryGetValue(key, out curValue))
+ return false;
+ dict.TryUpdate(key, updateFactory(curValue), curValue);
+ return true;//note we return true whether we succeed or not, see explanation below.
+ }
+
///
/// Converts a dictionary to another type by only using direct casting
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 3279f12251..6f23a9f69e 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -112,13 +112,15 @@
+
-
+
+