From cd0d841d50f86fccf2ebd896283babbe16f26e64 Mon Sep 17 00:00:00 2001 From: gravypower Date: Thu, 17 Jan 2013 13:39:01 +1100 Subject: [PATCH] Working on caching proxy updater updated the cache disabler --- .../Glass.Mapper.Sites.Sc.ncrunchproject | 5 + .../layouts/TestSub.ascx.cs | 6 - Source/Glass.Mapper.Sc/GlassConfig.cs | 2 - Source/Glass.Mapper/AbstractService.cs | 55 ++----- .../AbstractTypeCreationContext.cs | 2 - Source/Glass.Mapper/Caching/CacheDisabler.cs | 60 ++++++-- .../Caching/CacheKeyResolving/CacheKey.cs | 6 + .../Caching/CacheKeyResolving/ICacheKey.cs | 1 + .../ObjectCaching/AbstractObjectCache.cs | 28 +++- .../Caching/ObjectCaching/CacheInformation.cs | 139 ++++++++++++++---- .../ObjectCaching/IAbstractObjectCache.cs | 6 + .../Proxy/CacheLazyObjectInterceptor.cs | 49 ++++++ .../Caching/Proxy/CacheMethodInterceptor.cs | 42 +++++- .../Caching/Proxy/CacheProxyGenerator.cs | 24 +-- .../Caching/Proxy/CacheProxyGeneratorHook.cs | 5 +- .../AbstractObjectCacheConfiguration.cs | 2 +- Source/Glass.Mapper/Context.cs | 12 +- Source/Glass.Mapper/Glass.Mapper.csproj | 5 +- .../Proxy/CacheInterfaceMethodInterceptor.cs | 5 +- .../ObjectConstructionArgs.cs | 9 +- .../CreateConcrete/CreateConcreteTask.cs | 3 +- .../CreateConcrete/LazyObjectInterceptor.cs | 6 +- .../CreateInterface/CreateInterfaceTask.cs | 7 +- .../ObjectCachingResolverTask.cs | 5 +- .../ObjectCachingSaverTask.cs | 6 +- .../SetupSitecoreForTesting.cs | 76 +++++----- .../Caching/CacheInformationFixture.cs | 93 +++++++++--- .../Caching/ProxiesFixture.cs | 50 +++++++ .../Glass.Mapper.Tests.csproj | 1 + 29 files changed, 501 insertions(+), 209 deletions(-) create mode 100644 Source/Glass.Mapper/Caching/Proxy/CacheLazyObjectInterceptor.cs rename Source/Glass.Mapper/{Caching => ObjectCaching}/Proxy/CacheInterfaceMethodInterceptor.cs (96%) create mode 100644 Tests/Unit Tests/Glass.Mapper.Tests/Caching/ProxiesFixture.cs diff --git a/Sites/Sitecore/Glass.Mapper.Sites.Sc/Glass.Mapper.Sites.Sc.ncrunchproject b/Sites/Sitecore/Glass.Mapper.Sites.Sc/Glass.Mapper.Sites.Sc.ncrunchproject index 5db5b4e90..63322667c 100644 --- a/Sites/Sitecore/Glass.Mapper.Sites.Sc/Glass.Mapper.Sites.Sc.ncrunchproject +++ b/Sites/Sitecore/Glass.Mapper.Sites.Sc/Glass.Mapper.Sites.Sc.ncrunchproject @@ -17,4 +17,9 @@ AutoDetect + + + .* + + \ No newline at end of file diff --git a/Sites/Sitecore/Glass.Mapper.Sites.Sc/layouts/TestSub.ascx.cs b/Sites/Sitecore/Glass.Mapper.Sites.Sc/layouts/TestSub.ascx.cs index fb7f4e2b9..bac72a64c 100644 --- a/Sites/Sitecore/Glass.Mapper.Sites.Sc/layouts/TestSub.ascx.cs +++ b/Sites/Sitecore/Glass.Mapper.Sites.Sc/layouts/TestSub.ascx.cs @@ -1,12 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; using Glass.Mapper.Sc; using Glass.Mapper.Sc.Configuration.Attributes; -using Glass.Mapper.Sc.Integration; using Glass.Mapper.Sites.Sc.Models; namespace Glass.Mapper.Sites.Sc.layouts diff --git a/Source/Glass.Mapper.Sc/GlassConfig.cs b/Source/Glass.Mapper.Sc/GlassConfig.cs index a0dd6fcd0..7a4749119 100644 --- a/Source/Glass.Mapper.Sc/GlassConfig.cs +++ b/Source/Glass.Mapper.Sc/GlassConfig.cs @@ -142,8 +142,6 @@ public override void Configure(WindsorContainer container, string contextName) Component.For().ImplementedBy().LifestyleTransient(), - - Component.For().ImplementedBy().LifestyleTransient(), Component.For().ImplementedBy>().LifestyleTransient(), Component.For>().ImplementedBy().LifestyleTransient() diff --git a/Source/Glass.Mapper/AbstractService.cs b/Source/Glass.Mapper/AbstractService.cs index 7f7a31b00..6a62b16b4 100644 --- a/Source/Glass.Mapper/AbstractService.cs +++ b/Source/Glass.Mapper/AbstractService.cs @@ -16,18 +16,8 @@ namespace Glass.Mapper { public abstract class AbstractService : IAbstractService { - private IPerformanceProfiler _profiler; - /// - /// The list of tasks to be performed by the Object Construction Pipeline. Called in the order specified. - /// - private IEnumerable ObjectConstructionTasks { get; set; } - - /// - /// The list of tasks to be performed by the Object Construction Pipeline. Called in the order specified. - /// - private IEnumerable ObjectConstructionTasks { get; set; } public IPerformanceProfiler Profiler { get { return _profiler; } @@ -41,9 +31,7 @@ public IPerformanceProfiler Profiler } } - public Context GlassContext { get; private set; } - - + public Context GlassContext { get; private set; } private TypeResolver _typeResolver; @@ -52,7 +40,7 @@ public IPerformanceProfiler Profiler private ObjectConstruction _objectConstruction; private ObjectSaving _objectSaving; - + public AbstractService() : this(Context.Default) { @@ -69,17 +57,11 @@ public AbstractService(Context glassContext) GlassContext = glassContext; - if (GlassContext == null) + if (GlassContext == null) throw new NullReferenceException("Context is null"); - - ObjectConstructionTasks = glassContext.DependencyResolver.ResolveAllInOrder("Order"); - TypeResolverTasks = glassContext.DependencyResolver.ResolveAll(); - ConfigurationResolverTasks = glassContext.DependencyResolver.ResolveAll(); - ObjectSavingTasks = glassContext.DependencyResolver.ResolveAll(); - - var objectConstructionTasks = glassContext.DependencyResolver.ResolveAll(); - _objectConstruction = new ObjectConstruction(objectConstructionTasks); + var objectConstructionTasks = glassContext.DependencyResolver.ResolveAllInOrder("Order"); + _objectConstruction = new ObjectConstruction(objectConstructionTasks); var typeResolverTasks = glassContext.DependencyResolver.ResolveAll(); _typeResolver = new TypeResolver(typeResolverTasks); @@ -107,28 +89,17 @@ public object InstantiateObject(AbstractTypeCreationContext abstractTypeCreation //run the pipeline to get the configuration to load var configurationArgs = new ConfigurationResolverArgs(GlassContext, abstractTypeCreationContext, typeArgs.Result); _configurationResolver.Run(configurationArgs); - + if (configurationArgs.Result == null) throw new NullReferenceException("Configuration Resolver pipeline did not return type."); var config = configurationArgs.Result; //Run the object construction - _objectConstruction.Run(objectArgs); + var objectArgs = new ObjectConstructionArgs(GlassContext, abstractTypeCreationContext, config, this); - var objectArgs = new ObjectConstructionArgs(GlassContext, abstractTypeCreationContext, - config, this); - if (DisableCache) - { - using (new CacheDisabler(objectArgs)) - { - objectRunner.Run(objectArgs); - } - } - else - { - objectRunner.Run(objectArgs); - } + + _objectConstruction.Run(objectArgs); return objectArgs.Result; @@ -157,17 +128,13 @@ public void SaveObject(AbstractTypeSavingContext abstractTypeSavingContext) /// /// public abstract AbstractDataMappingContext CreateDataMappingContext(AbstractTypeSavingContext creationContext); - - - public bool DisableCache { get; set; } } public interface IAbstractService { - Context GlassContext { get; } + Context GlassContext { get; } object InstantiateObject(AbstractTypeCreationContext abstractTypeCreationContext); - /// /// Used to create the context used by DataMappers to map data to a class /// @@ -183,7 +150,5 @@ public interface IAbstractService /// The Saving Context /// AbstractDataMappingContext CreateDataMappingContext(AbstractTypeSavingContext creationContext); - - bool DisableCache { get; set; } } } diff --git a/Source/Glass.Mapper/AbstractTypeCreationContext.cs b/Source/Glass.Mapper/AbstractTypeCreationContext.cs index 6520584b6..d1662c075 100644 --- a/Source/Glass.Mapper/AbstractTypeCreationContext.cs +++ b/Source/Glass.Mapper/AbstractTypeCreationContext.cs @@ -12,8 +12,6 @@ namespace Glass.Mapper /// public abstract class AbstractTypeCreationContext { - - public bool InferType { get; set; } public bool IsLazy { get; set; } public Type RequestedType { get; set; } diff --git a/Source/Glass.Mapper/Caching/CacheDisabler.cs b/Source/Glass.Mapper/Caching/CacheDisabler.cs index 6e29601f3..dd6e15955 100644 --- a/Source/Glass.Mapper/Caching/CacheDisabler.cs +++ b/Source/Glass.Mapper/Caching/CacheDisabler.cs @@ -1,32 +1,66 @@ using System; +using System.Web; using Glass.Mapper.Pipelines.ObjectConstruction; namespace Glass.Mapper.Caching { public class CacheDisabler:IDisposable { - private readonly ObjectConstructionArgs _args; - private readonly IAbstractService _abstractService; - public CacheDisabler(ObjectConstructionArgs args) + public static bool CacheDisabled { - this._args = args; - args.DisableCache = true; + get + { + return HttpContext.Current != null ? ReturnFromHttpContxt() : ReturnFromThreadStatic(); + } + set + { + if (HttpContext.Current != null) + { + SetToHttpContext(value); + } + + SetToThreadStatic(value); + } } - public CacheDisabler(IAbstractService abstractService) + private static void SetToHttpContext(bool value) { - this._abstractService = abstractService; - _abstractService.DisableCache = true; + HttpContext.Current.Items["Glass_CacheDisabled"] = value; } - public void Dispose() + private static bool ReturnFromHttpContxt() + { + if (HttpContext.Current.Items.Contains("Glass_CacheDisabled")) + { + { + return (bool)HttpContext.Current.Items["Glass_CacheDisabled"]; + } + } + return false; + } + + [ThreadStatic] + private static bool _threadStaticCacheDisabled; + + private static void SetToThreadStatic(bool value) { - if(_args != null) - _args.DisableCache = false; + _threadStaticCacheDisabled = value; + } - if(_abstractService != null) - _abstractService.DisableCache = false; + private static bool ReturnFromThreadStatic() + { + return _threadStaticCacheDisabled; + } + + public CacheDisabler() + { + CacheDisabled = true; + } + + public void Dispose() + { + CacheDisabled = false; } } } diff --git a/Source/Glass.Mapper/Caching/CacheKeyResolving/CacheKey.cs b/Source/Glass.Mapper/Caching/CacheKeyResolving/CacheKey.cs index a13e292fb..a6421a64f 100644 --- a/Source/Glass.Mapper/Caching/CacheKeyResolving/CacheKey.cs +++ b/Source/Glass.Mapper/Caching/CacheKeyResolving/CacheKey.cs @@ -28,5 +28,11 @@ public override string ToString() } public abstract bool Equals(CacheKey other); + + + public object GetId() + { + return Id; + } } } diff --git a/Source/Glass.Mapper/Caching/CacheKeyResolving/ICacheKey.cs b/Source/Glass.Mapper/Caching/CacheKeyResolving/ICacheKey.cs index 6108018bf..f09919f39 100644 --- a/Source/Glass.Mapper/Caching/CacheKeyResolving/ICacheKey.cs +++ b/Source/Glass.Mapper/Caching/CacheKeyResolving/ICacheKey.cs @@ -3,5 +3,6 @@ public interface ICacheKey { bool Equals(object other); + object GetId(); } } \ No newline at end of file diff --git a/Source/Glass.Mapper/Caching/ObjectCaching/AbstractObjectCache.cs b/Source/Glass.Mapper/Caching/ObjectCaching/AbstractObjectCache.cs index 105a9910d..f684ef463 100644 --- a/Source/Glass.Mapper/Caching/ObjectCaching/AbstractObjectCache.cs +++ b/Source/Glass.Mapper/Caching/ObjectCaching/AbstractObjectCache.cs @@ -3,6 +3,7 @@ using System.Threading; using Glass.Mapper.Caching.CacheKeyResolving; using Glass.Mapper.Caching.ObjectCaching.Exceptions; +using Glass.Mapper.Caching.Proxy; using Glass.Mapper.Pipelines.ObjectConstruction; using System.Linq; @@ -10,9 +11,10 @@ namespace Glass.Mapper.Caching.ObjectCaching { public abstract class AbstractObjectCache : IAbstractObjectCache { - private readonly CacheInformation _cacheInformation = new CacheInformation(); + private readonly CacheInformation _cacheInformation = new CacheInformation(); public string BaseCacheKey { get; set; } - + + public string DefaultBaseCacheKey { get { return "GlassObjectCahe"; } @@ -26,7 +28,6 @@ public string DefaultBaseCacheKey protected abstract void InternalAddObject(string objectKey, object objectForCaching); protected abstract bool InternalClearCache(); - protected AbstractObjectCache(string baseCacheKey) { BaseCacheKey = baseCacheKey; @@ -64,6 +65,21 @@ public void AddObject(ObjectConstructionArgs args) InternalAddObject(CacheKeyResolver.GetKey(args).ToString(), args.Result); } + public object GetObject(ICacheKey cacheKey) + { + return InternalGetObject(cacheKey.ToString()); + } + + public bool ContansObject(ICacheKey cacheKey) + { + return InternalContansObject(cacheKey.ToString()); + } + + public void AddObject(ICacheKey cacheKey, object objectForCaching) + { + InternalAddObject(cacheKey.ToString(), objectForCaching); + } + public bool ClearCache() { return InternalClearCache(); @@ -181,5 +197,11 @@ public bool RemoveFromRelatedCache(string releatedKey) return InternalRemoveObject(releatedKey); } + + + public ICacheKey GetLatestCacheKey(object id) + { + return _cacheInformation.GetCacheKeys((TIdType)id).Peek(); + } } } diff --git a/Source/Glass.Mapper/Caching/ObjectCaching/CacheInformation.cs b/Source/Glass.Mapper/Caching/ObjectCaching/CacheInformation.cs index 49e581653..a47a51d33 100644 --- a/Source/Glass.Mapper/Caching/ObjectCaching/CacheInformation.cs +++ b/Source/Glass.Mapper/Caching/ObjectCaching/CacheInformation.cs @@ -1,4 +1,5 @@ -using System; +using Glass.Mapper.Caching.CacheKeyResolving; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,10 +7,11 @@ namespace Glass.Mapper.Caching.ObjectCaching { - public class CacheInformation + public class CacheInformation { private readonly int _timeout = 10000; - private readonly ReaderWriterLockSlim _readerWriterLock = new ReaderWriterLockSlim(); + private readonly ReaderWriterLockSlim _readerWriterLockRelatedKeys = new ReaderWriterLockSlim(); + private readonly ReaderWriterLockSlim _readerWriterLockCacheKey = new ReaderWriterLockSlim(); private volatile Dictionary> _relatedKeys; @@ -17,11 +19,14 @@ public class CacheInformation private volatile Dictionary> _objectKeysRelatedKeys; + private volatile Dictionary>> _idToCacheKey; + public CacheInformation() { _relatedKeys = new Dictionary>(); _objectKeysRelatedKeys = new Dictionary>(); _objectKeys = new List(); + _idToCacheKey = new Dictionary>>(); } public CacheInformation(int timeout) @@ -30,41 +35,110 @@ public CacheInformation(int timeout) _timeout = timeout; } + public Stack> GetCacheKeys(TIdType id) + { + using (var rel = new ReaderWriterLock(_readerWriterLockCacheKey, ReaderWriterLockType.Reader, _timeout)) + { + if (rel.HasTakenLock) + { + return GetCacheKeysKvp(id).Value; + } + } + //TODO: create an exception type + throw new Exception("Could not take lock"); + } - public void AddRelatedKey(string releatedKey) + public void AddCacheKey(TIdType id, CacheKey cacheKey) + { + using (var rel = new ReaderWriterLock(_readerWriterLockCacheKey, ReaderWriterLockType.Writer, _timeout)) + { + if (!rel.HasTakenLock) return; + InternalAddCacheKey(id, cacheKey); + } + } + + private void InternalAddCacheKey(TIdType id, CacheKey cacheKey) { - if (!ContainsRepeatedKey(releatedKey)) + if (!ContainsCacheKey(id)) { - InternalAddRepeatedKey(releatedKey); + _idToCacheKey.Add(id, new Stack>()); + } + + if (!_idToCacheKey[id].Contains(cacheKey)) + { + _idToCacheKey[id].Push(cacheKey); } } - private void InternalAddRepeatedKey(string relatedKey) + public bool ContainsCacheKey(TIdType id, CacheKey cacheKey) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockCacheKey, ReaderWriterLockType.Reader, _timeout)) { if (rel.HasTakenLock) { - _relatedKeys.Add(relatedKey, new List()); + return ContainsCacheKey(id) && GetCacheKeysKvp(id).Value.Any(x => x == cacheKey); } } + //TODO: create an exception type + throw new Exception("Could not take lock"); } - private bool ContainsRepeatedKey(string releatedKey) + public bool ContainsCacheKey(CacheKey cacheKey, List> cacheKeys) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Reader, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockCacheKey, ReaderWriterLockType.Reader, _timeout)) { if (rel.HasTakenLock) { - return _relatedKeys.ContainsKey(releatedKey); + return cacheKeys.Contains(cacheKey); + } + } + //TODO: create an exception type + throw new Exception("Could not take lock"); + } + + private bool ContainsCacheKey(TIdType id) + { + return !GetCacheKeysKvp(id).Equals(default(KeyValuePair>>)); + } + + private KeyValuePair>> GetCacheKeysKvp(TIdType id) + { + return GetCacheKeys().SingleOrDefault(x => x.Key.Equals(id)); + } + + private Dictionary>> GetCacheKeys() + { + return CloneDictionary(_idToCacheKey);; + } + + public void AddRelatedKey(string releatedKey) + { + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) + { + if (rel.HasTakenLock) + { + if (!ContainsRelatedKey(releatedKey)) + { + InternalAddRelatedKey(releatedKey); + } + } + } + } + + private void InternalAddRelatedKey(string relatedKey) + { + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) + { + if (rel.HasTakenLock) + { + _relatedKeys.Add(relatedKey, new List()); } } - return false; } private void AddRelatedKayAndObjectKey(string releatedKey, string objectKey) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { if (rel.HasTakenLock) { @@ -87,9 +161,9 @@ private void AddRelatedKayAndObjectKey(string releatedKey, string objectKey) public void AddObjectKey(string releatedKey, string objectKey) { - if (ContainsRepeatedKey(releatedKey)) + if (ContainsRelatedKey(releatedKey)) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { if (rel.HasTakenLock) { @@ -118,7 +192,7 @@ public void AddObjectKey(string releatedKey, string objectKey) public System.Collections.ICollection GetRelatedKeys() { var keyList = new List(); - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Reader, _timeout)) { if (rel.HasTakenLock) { @@ -129,9 +203,14 @@ public System.Collections.ICollection GetRelatedKeys() return keyList; } - private List CloneList(IEnumerable list) + private List CloneList(IEnumerable list) + { + return new List(list); + } + + private Dictionary CloneDictionary(IDictionary dictionary) { - return new List(list); + return new Dictionary(dictionary); } public System.Collections.ICollection Keys @@ -139,7 +218,7 @@ public System.Collections.ICollection Keys get { var returnKeyList = new List(); - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { if (rel.HasTakenLock) { @@ -163,13 +242,13 @@ public bool ContainsRelatedKey(string releatedKey) public void AddObjectKey(IEnumerable releatedKeys, string objectKey) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { if (!rel.HasTakenLock) return; foreach (var releatedKey in releatedKeys) { - if (ContainsRepeatedKey(releatedKey)) + if (ContainsRelatedKey(releatedKey)) { if (!_relatedKeys.ContainsKey(releatedKey)) { @@ -197,9 +276,9 @@ public void AddObjectKey(IEnumerable releatedKeys, string objectKey) public System.Collections.ICollection GetObjectKeys(string releatedKey) { List returnList; - using (new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { - returnList = new List(_relatedKeys[releatedKey]); + returnList = CloneList(_relatedKeys[releatedKey]); } return returnList; @@ -211,7 +290,7 @@ public System.Collections.ICollection GetObjectKeys(string releatedKey) /// The object key. public void RemoveObjectKey(string objectKey) { - using (var rel = new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (var rel = new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { _objectKeys.Remove(objectKey); @@ -224,13 +303,13 @@ public void RemoveObjectKey(string objectKey) _objectKeysRelatedKeys[objectKey].RemoveAll(x => x == relatedKey); } - if (this._relatedKeys.ContainsKey(relatedKey)) + if (_relatedKeys.ContainsKey(relatedKey)) { - this._relatedKeys[relatedKey].RemoveAll(x => x == objectKey); + _relatedKeys[relatedKey].RemoveAll(x => x == objectKey); } - if (!this._relatedKeys[relatedKey].Any()) - this._relatedKeys.Remove(relatedKey); + if (!_relatedKeys[relatedKey].Any()) + _relatedKeys.Remove(relatedKey); } @@ -240,7 +319,7 @@ public void RemoveObjectKey(string objectKey) public void RemoveRelatedKey(string relatedKey) { - using (new ReaderWriterLock(_readerWriterLock, ReaderWriterLockType.Writer, _timeout)) + using (new ReaderWriterLock(_readerWriterLockRelatedKeys, ReaderWriterLockType.Writer, _timeout)) { foreach (var objectKey in _relatedKeys[relatedKey]) { diff --git a/Source/Glass.Mapper/Caching/ObjectCaching/IAbstractObjectCache.cs b/Source/Glass.Mapper/Caching/ObjectCaching/IAbstractObjectCache.cs index 558f615f9..9ed4c208c 100644 --- a/Source/Glass.Mapper/Caching/ObjectCaching/IAbstractObjectCache.cs +++ b/Source/Glass.Mapper/Caching/ObjectCaching/IAbstractObjectCache.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Glass.Mapper.Caching.CacheKeyResolving; using Glass.Mapper.Pipelines.ObjectConstruction; namespace Glass.Mapper.Caching.ObjectCaching @@ -10,6 +11,9 @@ public interface IAbstractObjectCache object GetObject(ObjectConstructionArgs args); bool ContansObject(ObjectConstructionArgs args); void AddObject(ObjectConstructionArgs args); + object GetObject(ICacheKey cacheKey); + bool ContansObject(ICacheKey cacheKey); + void AddObject(ICacheKey cacheKey, object objectForCaching); bool ClearCache(); object GetFromRelatedCache(string objectKey); @@ -19,5 +23,7 @@ public interface IAbstractObjectCache bool ClearRelatedCache(string releatedKey); bool RemoveFromRelatedCache(string releatedKey); IDictionary> GetRelatedKeys(); + + ICacheKey GetLatestCacheKey(object id); } } \ No newline at end of file diff --git a/Source/Glass.Mapper/Caching/Proxy/CacheLazyObjectInterceptor.cs b/Source/Glass.Mapper/Caching/Proxy/CacheLazyObjectInterceptor.cs new file mode 100644 index 000000000..fad0d6176 --- /dev/null +++ b/Source/Glass.Mapper/Caching/Proxy/CacheLazyObjectInterceptor.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Castle.DynamicProxy; +using Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete; + +namespace Glass.Mapper.Caching.Proxy +{ + public class CacheLazyObjectInterceptor: IInterceptor + { + Dictionary _values = new Dictionary(); + + LazyObjectInterceptor _subInterceptor; + + public CacheLazyObjectInterceptor(LazyObjectInterceptor subInterceptor) + { + _subInterceptor = subInterceptor; + } + + public void Intercept(Castle.DynamicProxy.IInvocation invocation) + { + + if (invocation.Method.IsSpecialName) + { + if (invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_")) + { + + string method = invocation.Method.Name.Substring(0, 4); + string name = invocation.Method.Name.Substring(4); + + if (method == "get_" && _values.ContainsKey(name)) + { + invocation.ReturnValue = _values[name]; + return; + } + else if (method == "set_") + { + _values[name] = invocation.Arguments[0]; + return; + } + } + + } + + _subInterceptor.Intercept(invocation); + } + } +} diff --git a/Source/Glass.Mapper/Caching/Proxy/CacheMethodInterceptor.cs b/Source/Glass.Mapper/Caching/Proxy/CacheMethodInterceptor.cs index 0adda1240..9496fd665 100644 --- a/Source/Glass.Mapper/Caching/Proxy/CacheMethodInterceptor.cs +++ b/Source/Glass.Mapper/Caching/Proxy/CacheMethodInterceptor.cs @@ -1,27 +1,53 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Castle.DynamicProxy; -using Glass.Mapper.Configuration; +using Glass.Mapper.Caching.CacheKeyResolving; +using Glass.Mapper.Caching.ObjectCaching; +using Glass.Mapper.Pipelines.ObjectConstruction; -namespace Glass.Mapper.ObjectCaching.Proxy +namespace Glass.Mapper.Caching.Proxy { public class CacheMethodInterceptor : IInterceptor { - private readonly Dictionary _values; - private readonly object _originalTarget; + private Dictionary _values; + private object _originalTarget; + private ICacheKey _cacheKey; - public CacheMethodInterceptor(object originalTarget) + public static DateTime LastUpdated { get; set; } + + private DateTime _lastUpdated; + + + static CacheMethodInterceptor() + { + LastUpdated = DateTime.Now; + } + + public CacheMethodInterceptor(object originalTarget, ObjectConstructionArgs args) { _values = new Dictionary(); - _originalTarget = originalTarget; + _originalTarget = originalTarget; + _lastUpdated = DateTime.Now; + _cacheKey = args.CacheKey; } #region IInterceptor Members public void Intercept(IInvocation invocation) { + if (LastUpdated > _lastUpdated) + { + var newCacheKey = + Context.Default.ObjectCacheConfiguration.ObjectCache.GetLatestCacheKey(_cacheKey.GetId()); + if (newCacheKey.Equals(_cacheKey)) + { + + _originalTarget = Context.Default.ObjectCacheConfiguration.ObjectCache.GetObject(newCacheKey); + _values = new Dictionary(); + _cacheKey = newCacheKey; + } + } + if (invocation.Method.IsSpecialName) { if (invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_")) diff --git a/Source/Glass.Mapper/Caching/Proxy/CacheProxyGenerator.cs b/Source/Glass.Mapper/Caching/Proxy/CacheProxyGenerator.cs index a6f4154d8..4d55da39c 100644 --- a/Source/Glass.Mapper/Caching/Proxy/CacheProxyGenerator.cs +++ b/Source/Glass.Mapper/Caching/Proxy/CacheProxyGenerator.cs @@ -2,6 +2,7 @@ using System.Linq; using Castle.DynamicProxy; using Glass.Mapper.ObjectCaching.Proxy; +using Glass.Mapper.Pipelines.ObjectConstruction; using Glass.Mapper.Proxies; namespace Glass.Mapper.Caching.Proxy @@ -9,16 +10,14 @@ namespace Glass.Mapper.Caching.Proxy public class CacheProxyGenerator { - private static readonly ProxyGenerator _generator = new ProxyGenerator(); - private static readonly ProxyGenerationOptions _options = new ProxyGenerationOptions(new CacheProxyGeneratorHook()); + private static readonly ProxyGenerator Generator = new ProxyGenerator(); + private static readonly ProxyGenerationOptions Options = new ProxyGenerationOptions(new CacheProxyGeneratorHook()); - public static object CreateProxy(object originalTarget) + public static object CreateProxy(object originalTarget, ObjectConstructionArgs args) { Type type = originalTarget.GetType(); - object proxy = null ; - //you can't proxy a proxy. if (originalTarget is IProxyTargetAccessor) { @@ -28,23 +27,14 @@ public static object CreateProxy(object originalTarget) { var subInterceptor = interceptors.First(x => x is InterfaceMethodInterceptor).CastTo(); - return _generator.CreateInterfaceProxyWithoutTarget( + return Generator.CreateInterfaceProxyWithoutTarget( type, new CacheInterfaceMethodInterceptor(subInterceptor)); } - else if (interceptors.Any(x => x is ProxyClassInterceptor)) - { - - } - - } - else - { - proxy = _generator.CreateClassProxy(type, _options, new CacheMethodInterceptor(originalTarget)); + return oldProxy; } - - return proxy; + return Generator.CreateClassProxy(type, Options, new CacheMethodInterceptor(originalTarget, args)); } } } diff --git a/Source/Glass.Mapper/Caching/Proxy/CacheProxyGeneratorHook.cs b/Source/Glass.Mapper/Caching/Proxy/CacheProxyGeneratorHook.cs index 9cc2300c7..05fca216a 100644 --- a/Source/Glass.Mapper/Caching/Proxy/CacheProxyGeneratorHook.cs +++ b/Source/Glass.Mapper/Caching/Proxy/CacheProxyGeneratorHook.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Castle.DynamicProxy; -namespace Glass.Mapper.ObjectCaching.Proxy +namespace Glass.Mapper.Caching.Proxy { public class CacheProxyGeneratorHook : IProxyGenerationHook { diff --git a/Source/Glass.Mapper/Configuration/AbstractObjectCacheConfiguration.cs b/Source/Glass.Mapper/Configuration/AbstractObjectCacheConfiguration.cs index 58d45a156..b6f5986b2 100644 --- a/Source/Glass.Mapper/Configuration/AbstractObjectCacheConfiguration.cs +++ b/Source/Glass.Mapper/Configuration/AbstractObjectCacheConfiguration.cs @@ -23,7 +23,7 @@ protected AbstractObjectCacheConfiguration(string contextName) protected AbstractObjectCacheConfiguration(Context glassContext) { - ObjectCache = glassContext.DependencyResolver.TryResolve(); + ObjectCache = glassContext.DependencyResolver.TryResolve(); } } } diff --git a/Source/Glass.Mapper/Context.cs b/Source/Glass.Mapper/Context.cs index e84fe8142..cbfca7208 100644 --- a/Source/Glass.Mapper/Context.cs +++ b/Source/Glass.Mapper/Context.cs @@ -53,6 +53,7 @@ public static Context Create(IGlassConfiguration glassConfig) /// /// Creates a new context and adds it to the Contexts dictionary. /// + /// /// The context name, used as the key in the Contexts dictionary. /// Indicates if this is the default context. If it is the context is assigned to the Default static property. /// @@ -66,13 +67,20 @@ public static Context Create(IGlassConfiguration glassConfig, string contextName context.DependencyResolver = ResolverFactory.GetResolver(); context.DependencyResolver.Load(contextName, glassConfig); - context.ObjectCacheConfiguration = context.DependencyResolver.TryResolve(); - Contexts[contextName] = context; if (isDefault) Default = context; + context.ObjectCacheConfiguration = + context.DependencyResolver.TryResolve(new Dictionary + { + { + "glassContext", + context + } + }); + return context; } diff --git a/Source/Glass.Mapper/Glass.Mapper.csproj b/Source/Glass.Mapper/Glass.Mapper.csproj index 5f7f4cc02..80b8b47f9 100644 --- a/Source/Glass.Mapper/Glass.Mapper.csproj +++ b/Source/Glass.Mapper/Glass.Mapper.csproj @@ -79,7 +79,7 @@ - + @@ -117,6 +117,7 @@ + @@ -173,4 +174,4 @@ --> - + \ No newline at end of file diff --git a/Source/Glass.Mapper/Caching/Proxy/CacheInterfaceMethodInterceptor.cs b/Source/Glass.Mapper/ObjectCaching/Proxy/CacheInterfaceMethodInterceptor.cs similarity index 96% rename from Source/Glass.Mapper/Caching/Proxy/CacheInterfaceMethodInterceptor.cs rename to Source/Glass.Mapper/ObjectCaching/Proxy/CacheInterfaceMethodInterceptor.cs index 4effaeb5a..4a650d722 100644 --- a/Source/Glass.Mapper/Caching/Proxy/CacheInterfaceMethodInterceptor.cs +++ b/Source/Glass.Mapper/ObjectCaching/Proxy/CacheInterfaceMethodInterceptor.cs @@ -1,9 +1,6 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Glass.Mapper.Proxies; using Castle.DynamicProxy; +using Glass.Mapper.Proxies; namespace Glass.Mapper.ObjectCaching.Proxy { diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/ObjectConstructionArgs.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/ObjectConstructionArgs.cs index a2a356e76..c3c4bffb4 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/ObjectConstructionArgs.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/ObjectConstructionArgs.cs @@ -1,4 +1,5 @@ -using Glass.Mapper.Configuration; +using Glass.Mapper.Caching.CacheKeyResolving; +using Glass.Mapper.Configuration; namespace Glass.Mapper.Pipelines.ObjectConstruction { @@ -14,14 +15,12 @@ public class ObjectConstructionArgs : AbstractPipelineArgs /// public AbstractTypeConfiguration Configuration { get; private set; } - - - public bool DisableCache { get; internal set; } - public IAbstractService Service { get; private set; } public virtual object Result { get; set; } + public ICacheKey CacheKey{ get; set; } + public ObjectOrigin ObjectOrigin { get; set; } public ObjectConstructionArgs() : base() diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/CreateConcreteTask.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/CreateConcreteTask.cs index 8c9966d89..9d27c6ef8 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/CreateConcreteTask.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/CreateConcreteTask.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Text; using Castle.DynamicProxy; +using Glass.Mapper.Caching; using Glass.Mapper.Profilers; namespace Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete @@ -48,7 +49,7 @@ public override void Execute(ObjectConstructionArgs args) args.ObjectOrigin = ObjectOrigin.CreateConcrete; } - if (args.DisableCache || args.Context.ObjectCacheConfiguration == null) + if (CacheDisabler.CacheDisabled || args.Context.ObjectCacheConfiguration == null) { args.AbortPipeline(); } diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/LazyObjectInterceptor.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/LazyObjectInterceptor.cs index bb80ac3a7..45086566c 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/LazyObjectInterceptor.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateConcrete/LazyObjectInterceptor.cs @@ -1,4 +1,5 @@ using Castle.DynamicProxy; +using Glass.Mapper.Caching; namespace Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete { @@ -24,7 +25,10 @@ public void Intercept(IInvocation invocation) if (_actual == null) { _args.AbstractTypeCreationContext.IsLazy = false; - _actual = _args.Service.InstantiateObject(_args.AbstractTypeCreationContext); + using (new CacheDisabler()) + { + _actual = _args.Service.InstantiateObject(_args.AbstractTypeCreationContext); + } } invocation.ReturnValue = invocation.Method.Invoke(_actual, invocation.Arguments); diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateInterface/CreateInterfaceTask.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateInterface/CreateInterfaceTask.cs index 42ac598ce..d56d4b3f3 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateInterface/CreateInterfaceTask.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/CreateInterface/CreateInterfaceTask.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using Castle.DynamicProxy; +using Glass.Mapper.Caching; namespace Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateInterface { @@ -33,7 +34,11 @@ public override void Execute(ObjectConstructionArgs args) { args.Result = _generator.CreateInterfaceProxyWithoutTarget(args.Configuration.Type, new InterfacePropertyInterceptor(args)); args.ObjectOrigin = ObjectOrigin.CreateInterface; - args.AbortPipeline(); + + if (CacheDisabler.CacheDisabled || args.Context.ObjectCacheConfiguration == null) + { + args.AbortPipeline(); + } } } } diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingResolver/ObjectCachingResolverTask.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingResolver/ObjectCachingResolverTask.cs index 91f1e610b..fce6476bc 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingResolver/ObjectCachingResolverTask.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingResolver/ObjectCachingResolverTask.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Glass.Mapper.Caching; using Glass.Mapper.Caching.Proxy; namespace Glass.Mapper.Pipelines.ObjectConstruction.Tasks.ObjectCachingResolver @@ -10,13 +11,13 @@ public class ObjectCachingResolverTask : ObjectConstructionTask { public override void Execute(ObjectConstructionArgs args) { - if (args.DisableCache) return; + if (CacheDisabler.CacheDisabled) return; if (args.Context.ObjectCacheConfiguration == null) return; if (!args.Context.ObjectCacheConfiguration.ObjectCache.ContansObject(args)) return; - args.Result = args.Context.ObjectCacheConfiguration.ObjectCache.GetObject(args); + args.Result = CacheProxyGenerator.CreateProxy(args.Context.ObjectCacheConfiguration.ObjectCache.GetObject(args), args); args.ObjectOrigin = ObjectOrigin.ObjectCachingResolver; args.AbortPipeline(); } diff --git a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingSaver/ObjectCachingSaverTask.cs b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingSaver/ObjectCachingSaverTask.cs index 0b7c7ef0c..420c7e148 100644 --- a/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingSaver/ObjectCachingSaverTask.cs +++ b/Source/Glass.Mapper/Pipelines/ObjectConstruction/Tasks/ObjectCachingSaver/ObjectCachingSaverTask.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Glass.Mapper.Caching; using Glass.Mapper.Caching.Proxy; namespace Glass.Mapper.Pipelines.ObjectConstruction.Tasks.ObjectCachingSaver @@ -10,12 +11,11 @@ public class ObjectCachingSaverTask : ObjectConstructionTask { public override void Execute(ObjectConstructionArgs args) { - if (args.DisableCache) return; + if (CacheDisabler.CacheDisabled) return; //Save item to the cache args.Context.ObjectCacheConfiguration.ObjectCache.AddObject(args); - - args.Result = CacheProxyGenerator.CreateProxy(args.Result); + args.Result = CacheProxyGenerator.CreateProxy(args.Result, args); } } } diff --git a/Tests/Integration Tests/Sitecore/Glass.Mapper.Sc.Integration/SetupSitecoreForTesting.cs b/Tests/Integration Tests/Sitecore/Glass.Mapper.Sc.Integration/SetupSitecoreForTesting.cs index c277b9088..78dd29fe3 100644 --- a/Tests/Integration Tests/Sitecore/Glass.Mapper.Sc.Integration/SetupSitecoreForTesting.cs +++ b/Tests/Integration Tests/Sitecore/Glass.Mapper.Sc.Integration/SetupSitecoreForTesting.cs @@ -17,49 +17,49 @@ namespace Glass.Mapper.Sc.Integration [SetUpFixture] public class SetupSitecoreForTesting { - [SetUp] - public void DeployTestItems() - { - System.Threading.Thread.CurrentThread.ExecutionContext.GetObjectData(); - //We need to locate the TDS project that contains our test configuration. We are assuming its folder is a sibling of the project folder and we are in the /bin/[config] folder - string currentPath = Environment.CurrentDirectory; - string tdsProjectPath = Path.GetFullPath(Path.Combine(currentPath, "..\\..\\..\\Glass.Mapper.Sc.Integration.Tds")); + //[SetUp] + //public void DeployTestItems() + //{ + // //System.Threading.Thread.CurrentThread.ExecutionContext.GetObjectData(); + // //We need to locate the TDS project that contains our test configuration. We are assuming its folder is a sibling of the project folder and we are in the /bin/[config] folder + // string currentPath = Environment.CurrentDirectory; + // string tdsProjectPath = Path.GetFullPath(Path.Combine(currentPath, "..\\..\\..\\Glass.Mapper.Sc.Integration.Tds")); - string msBuildPath = ConfigurationManager.AppSettings["MSBuildPath"]; + // string msBuildPath = ConfigurationManager.AppSettings["MSBuildPath"]; - ProcessStartInfo psi = new ProcessStartInfo - { - UseShellExecute = false, - FileName = Path.Combine(msBuildPath, "MSBuild.exe"), - Arguments = "/t:Deploy Glass.Mapper.Sc.Integration.Tds.scproj", - RedirectStandardOutput = true, - RedirectStandardError = true, - WorkingDirectory = tdsProjectPath - }; + // ProcessStartInfo psi = new ProcessStartInfo + // { + // UseShellExecute = false, + // FileName = Path.Combine(msBuildPath, "MSBuild.exe"), + // Arguments = "/t:Deploy Glass.Mapper.Sc.Integration.Tds.scproj", + // RedirectStandardOutput = true, + // RedirectStandardError = true, + // WorkingDirectory = tdsProjectPath + // }; - //Start the TDS deploy - using (Process buildProc = Process.Start(psi)) - { - //Show the output in the console for debugging purposes - while (!buildProc.HasExited) - { - string output = buildProc.StandardOutput.ReadLine(); - Debug.WriteLine(output); - Console.WriteLine(output); - } + // //Start the TDS deploy + // using (Process buildProc = Process.Start(psi)) + // { + // //Show the output in the console for debugging purposes + // while (!buildProc.HasExited) + // { + // string output = buildProc.StandardOutput.ReadLine(); + // Debug.WriteLine(output); + // Console.WriteLine(output); + // } - //If there are any failues, show the standard error contents - if (buildProc.ExitCode != 0) - { - Console.WriteLine("\n\nStandard Error:"); + // //If there are any failues, show the standard error contents + // if (buildProc.ExitCode != 0) + // { + // Console.WriteLine("\n\nStandard Error:"); - while (!buildProc.StandardError.EndOfStream) - { - Console.WriteLine(buildProc.StandardError.ReadLine()); - } - } - } - } + // while (!buildProc.StandardError.EndOfStream) + // { + // Console.WriteLine(buildProc.StandardError.ReadLine()); + // } + // } + // } + //} } } #endif diff --git a/Tests/Unit Tests/Glass.Mapper.Tests/Caching/CacheInformationFixture.cs b/Tests/Unit Tests/Glass.Mapper.Tests/Caching/CacheInformationFixture.cs index 3495f0e56..eb8bd0642 100644 --- a/Tests/Unit Tests/Glass.Mapper.Tests/Caching/CacheInformationFixture.cs +++ b/Tests/Unit Tests/Glass.Mapper.Tests/Caching/CacheInformationFixture.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Glass.Mapper.Caching.CacheKeyResolving; using Glass.Mapper.Caching.ObjectCaching; +using NSubstitute; using NUnit.Framework; namespace Glass.Mapper.Tests.Caching @@ -15,7 +17,7 @@ public class CacheInformationFixture [Test] public void Can_Create_CreateCacheInformation() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); Assert.IsNotNull(ci); } @@ -23,7 +25,7 @@ public void Can_Create_CreateCacheInformation() [Test] public void Can_Add_Related_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Related_Key"; ci.AddRelatedKey(releatedKey); @@ -34,7 +36,7 @@ public void Can_Add_Related_Key() [Test] public void Can_Add_Related_Key_Thread_Safe() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Related_Key"; @@ -53,7 +55,7 @@ public void Can_Add_Related_Key_Thread_Safe() [Test] public void Can_Add_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; ci.AddObjectKey(releatedKey, key); @@ -64,7 +66,7 @@ public void Can_Add_Key() [Test] public void Can_Add_Key_Thread_Safe() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; @@ -84,7 +86,7 @@ public void Can_Add_Key_Thread_Safe() [Test] public void Does_CacheInformation_Contain_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; ci.AddObjectKey(releatedKey, key); @@ -97,7 +99,7 @@ public void Does_CacheInformation_Contain_Key() [Test] public void Does_CacheInformation_Contain_Related_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; ci.AddObjectKey(releatedKey, key); @@ -111,7 +113,7 @@ public void Does_CacheInformation_Contain_Related_Key() [Test] public void Does_CacheInformation_Contain_Key_Thread_Safe() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; ci.AddObjectKey(releatedKey, key); @@ -135,11 +137,11 @@ public void Does_CacheInformation_Contain_Key_Thread_Safe() [Test] public void Test_LookUp_Time_For_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key = "Can_Add_Key"; - Parallel.For(0, 100000, i => + Parallel.For(0, 1000, i => { ci.AddObjectKey(releatedKey + i, key + i); }); @@ -156,7 +158,7 @@ public void Test_LookUp_Time_For_Key() [Test] public void Can_Get_Add_List_Of_Related_Keys_With_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var relatedKey1 = "Related_Key1"; var relatedKey2 = "Related_Key2"; @@ -172,7 +174,7 @@ public void Can_Get_Add_List_Of_Related_Keys_With_Key() [Test] public void Can_Get_List_Of_Related_Keys_From_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Add_Key_Related_Key"; var key1 = "key1"; @@ -190,7 +192,7 @@ public void Can_Get_List_Of_Related_Keys_From_Key() [Test] public void Can_Remove_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Remove_Key_Related_Key"; var key = "Can_Remove_Key"; ci.AddObjectKey(releatedKey, key); @@ -206,7 +208,7 @@ public void Can_Remove_Key() [Test] public void Can_Remove_Key_By_Related_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Remove_Key_Related_Key"; var key = "Can_Remove_Key"; ci.AddObjectKey(releatedKey, key); @@ -221,7 +223,7 @@ public void Can_Remove_Key_By_Related_Key() [Test] public void Related_Key_Is_Removed_When_Remove_Key_By_Related_Key() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Remove_Key_Related_Key"; var key = "Can_Remove_Key"; ci.AddObjectKey(releatedKey, key); @@ -236,7 +238,7 @@ public void Related_Key_Is_Removed_When_Remove_Key_By_Related_Key() [Test] public void Related_Key_Is_Removed_When_No_Keys_Are_Left() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Remove_Key_Related_Key"; var key = "Can_Remove_Key"; ci.AddObjectKey(releatedKey, key); @@ -252,7 +254,7 @@ public void Related_Key_Is_Removed_When_No_Keys_Are_Left() [Test] public void Related_Key_Is_Removed_When_No_Keys_Are_Left_Thread_Safe() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var releatedKey = "Can_Remove_Key_Related_Key"; var key = "Can_Remove_Key"; @@ -275,7 +277,7 @@ public void Related_Key_Is_Removed_When_No_Keys_Are_Left_Thread_Safe() [Test] public void List_Related_Key_Is_Removed_When_No_Keys_Are_Left() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var relatedKey1 = "Related_Key1"; var relatedKey2 = "Related_Key2"; @@ -297,7 +299,7 @@ public void List_Related_Key_Is_Removed_When_No_Keys_Are_Left() [Test] public void List_Related_Key_Is_Removed_When_No_Keys_Are_Left_Thread_Safe() { - var ci = new CacheInformation(); + var ci = new CacheInformation(); var relatedKey1 = "Related_Key1"; var relatedKey2 = "Related_Key2"; @@ -317,10 +319,63 @@ public void List_Related_Key_Is_Removed_When_No_Keys_Are_Left_Thread_Safe() Assert.IsFalse(((List)ci.GetRelatedKeys()).Any(x => x == relatedKey1 + i)); Assert.IsFalse(((List)ci.GetRelatedKeys()).Any(x => x == relatedKey2 + i)); }); + } + + [Test] + public void Can_Add_CacheKey() + { + var ci = new CacheInformation(); + var id = 1; + var ck = Substitute.For>(id, 1, "", typeof(StubClass)); + ci.AddCacheKey(id, ck); + + Assert.IsTrue(ci.ContainsCacheKey(id, ck)); + } + + [Test] + public void Can_Add_CacheKey_Thread_Safe() + { + var ci = new CacheInformation(); + Parallel.For(0, 10000, i => + { + var id = i; + var ck = Substitute.For>(id, i, "", typeof (StubClass)); + ci.AddCacheKey(id, ck); + + Assert.IsTrue(ci.ContainsCacheKey(id, ck)); + }); + } + + + [Test] + public void Can_Get_CacheKey() + { + var ci = new CacheInformation(); + var id = 1; + var ck = Substitute.For>(id, 1, "", typeof(StubClass)); + ci.AddCacheKey(id, ck); + + Assert.IsTrue(ci.ContainsCacheKey(id, ck)); + Assert.AreEqual(ck, ci.GetCacheKeys(id).First()); + } + #region Stubs + + public class StubClass + { + + public string MyProperty { get; set; } } + public interface IStubInterface + { + + } + + + + #endregion } } diff --git a/Tests/Unit Tests/Glass.Mapper.Tests/Caching/ProxiesFixture.cs b/Tests/Unit Tests/Glass.Mapper.Tests/Caching/ProxiesFixture.cs new file mode 100644 index 000000000..e43f3d029 --- /dev/null +++ b/Tests/Unit Tests/Glass.Mapper.Tests/Caching/ProxiesFixture.cs @@ -0,0 +1,50 @@ +using Glass.Mapper.Caching.CacheKeyResolving; +using Glass.Mapper.Caching.Proxy; +using Glass.Mapper.Pipelines.ObjectConstruction; +using NSubstitute; +using NUnit.Framework; + +namespace Glass.Mapper.Tests.Caching +{ + [TestFixture] + public class ProxiesFixture + { + private CacheKey _cacheKey; + private ObjectConstructionArgs _args; + private AbstractCacheKeyResolver _cacheKeyResolver; + + [SetUp] + public void SetUp() + { + _cacheKey = Substitute.For>(); + _args = Substitute.For(); + _cacheKeyResolver = Substitute.For>(); + _cacheKeyResolver.GetKey(_args).Returns(_cacheKey); + } + + [Test] + public void Can_Create_Proxy_For_Object() + { + var test = new StubClass(); + CacheProxyGenerator.CreateProxy(test, _args); + } + + #region Stubs + + public class StubClass + { + + public string MyProperty { get; set; } + } + + public interface IStubInterface + { + + } + + + + + #endregion + } +} diff --git a/Tests/Unit Tests/Glass.Mapper.Tests/Glass.Mapper.Tests.csproj b/Tests/Unit Tests/Glass.Mapper.Tests/Glass.Mapper.Tests.csproj index c625d5d19..7c0048bde 100644 --- a/Tests/Unit Tests/Glass.Mapper.Tests/Glass.Mapper.Tests.csproj +++ b/Tests/Unit Tests/Glass.Mapper.Tests/Glass.Mapper.Tests.csproj @@ -70,6 +70,7 @@ +