diff --git a/src/Umbraco.Core/CacheRefreshersResolver.cs b/src/Umbraco.Core/CacheRefreshersResolver.cs index fc30e05a64..5ab724fbab 100644 --- a/src/Umbraco.Core/CacheRefreshersResolver.cs +++ b/src/Umbraco.Core/CacheRefreshersResolver.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using LightInject; using Umbraco.Core.Logging; using Umbraco.Core.ObjectResolution; using Umbraco.Core.Cache; @@ -11,36 +13,34 @@ namespace Umbraco.Core /// /// A resolver to return all ICacheRefresher objects /// - internal sealed class CacheRefreshersResolver : LegacyTransientObjectsResolver + internal sealed class CacheRefreshersResolver : ContainerLazyManyObjectsResolver { /// /// Constructor /// - /// + /// /// /// - internal CacheRefreshersResolver(IServiceProvider serviceProvider, ILogger logger, Func> refreshers) - : base(serviceProvider, logger, refreshers) + internal CacheRefreshersResolver(IServiceContainer serviceContainer, ILogger logger, Func> refreshers) + : base(serviceContainer, logger, refreshers) { } - - + /// /// Gets the implementations. /// - public IEnumerable CacheRefreshers - { - get - { - EnsureIsInitialized(); - return Values; - } - } + public IEnumerable CacheRefreshers => Values; - protected override Guid GetUniqueIdentifier(ICacheRefresher obj) - { - return obj.UniqueIdentifier; - } + /// + /// Returns an instance for the type identified by its unique type identifier. + /// + /// The type identifier. + /// The value of the type uniquely identified by . + public ICacheRefresher GetById(Guid id) + { + return Values.FirstOrDefault(x => x.UniqueIdentifier == id); + } + } } diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 61947ac165..e46e87558c 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -437,7 +437,7 @@ namespace Umbraco.Core // new RepositoryFactory(ApplicationCache)); CacheRefreshersResolver.Current = new CacheRefreshersResolver( - ServiceProvider, ProfilingLogger.Logger, + Container, ProfilingLogger.Logger, () => PluginManager.ResolveCacheRefreshers()); PackageActionsResolver.Current = new PackageActionsResolver( diff --git a/src/Umbraco.Core/Models/ContentTypeExtensions.cs b/src/Umbraco.Core/Models/ContentTypeExtensions.cs index 6301b46950..ea6a28eb37 100644 --- a/src/Umbraco.Core/Models/ContentTypeExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeExtensions.cs @@ -10,10 +10,11 @@ namespace Umbraco.Core.Models /// Get all descendant content types /// /// + /// /// - public static IEnumerable Descendants(this IContentTypeBase contentType) - { - var contentTypeService = ApplicationContext.Current.Services.ContentTypeService; + public static IEnumerable Descendants(this TItem contentType, IContentTypeServiceBase contentTypeService) + where TItem : IContentTypeComposition + { var descendants = contentTypeService.GetChildren(contentType.Id) .SelectRecursive(type => contentTypeService.GetChildren(type.Id)); return descendants; @@ -23,22 +24,14 @@ namespace Umbraco.Core.Models /// Get all descendant and self content types /// /// + /// /// - public static IEnumerable DescendantsAndSelf(this IContentTypeBase contentType) + public static IEnumerable DescendantsAndSelf(this TItem contentType, IContentTypeServiceBase contentTypeService) + where TItem : IContentTypeComposition { - var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants()); + var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants(contentTypeService)); return descendantsAndSelf; } - - ///// - ///// Returns the descendant content type Ids for the given content type - ///// - ///// - ///// - //public static IEnumerable DescendantIds(this IContentTypeBase contentType) - //{ - // return ((ContentTypeService) ApplicationContext.Current.Services.ContentTypeService) - // .GetDescendantContentTypeIds(contentType.Id); - //} + } } \ No newline at end of file diff --git a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs b/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs deleted file mode 100644 index 62ce20cbbb..0000000000 --- a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; -using Umbraco.Core.Logging; - -namespace Umbraco.Core.ObjectResolution -{ - /// - /// The base class for old legacy factories such as the DataTypeFactory or CacheResolverFactory. - /// - /// The type of the concrete resolver class. - /// The type of the resolved objects. - /// - /// This class contains basic functionality to mimic the functionality in these old factories since they all return - /// transient objects (though this should be changed) and the method GetById needs to lookup a type to an ID and since - /// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this - /// for use in the GetById method. - /// - internal abstract class LegacyTransientObjectsResolver : LazyManyObjectsResolverBase - where TResolved : class - where TResolver : ResolverBase - { - private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); - private ConcurrentDictionary _id2Type; - - #region Constructors - - /// - /// Initializes a new instance of the class with an initial list of object types. - /// - /// - /// - /// A function returning the list of object types. - /// - /// We are creating Transient instances (new instances each time) because this is how the legacy code worked and - /// I don't want to muck anything up by changing them to application based instances. - /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. - /// - protected LegacyTransientObjectsResolver(IServiceProvider serviceProvider, ILogger logger, Func> value) - : base(serviceProvider, logger, value, ObjectLifetimeScope.Transient) // new objects every time - { } - #endregion - - /// - /// Returns the unique identifier of the type of a specified object. - /// - /// The object. - /// The unique identifier of the type of . - protected abstract Guid GetUniqueIdentifier(TResolved value); - - /// - /// Returns a new instance for the type identified by its unique type identifier. - /// - /// The type identifier. - /// The value of the type uniquely identified by . - public TResolved GetById(Guid id) - { - EnsureIsInitialized(); - return _id2Type.ContainsKey(id) == false - ? null - : ServiceProvider.GetService(_id2Type[id]) as TResolved; - } - - /// - /// Populates the identifiers-to-types dictionnary. - /// - /// - /// This allow us to instantiate a type by ID since these legacy types doesn't contain any metadata. - /// We instanciate all types once to get their unique identifier, then build the dictionary so that - /// when GetById is called, we can instanciate a single object. - /// - protected void EnsureIsInitialized() - { - using (var l = new UpgradeableReadLock(_lock)) - { - if (_id2Type == null) - { - l.UpgradeToWriteLock(); - - _id2Type = new ConcurrentDictionary(); - foreach (var value in Values) - { - _id2Type.TryAdd(GetUniqueIdentifier(value), value.GetType()); - } - } - } - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs index 93b323b1a7..04216f558a 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs @@ -62,9 +62,35 @@ namespace Umbraco.Core.Services } else { - //if a property was deleted or alias changed, then update all content of the current content type - // and all of it's desscendant doc types. - toUpdate.AddRange(contentType.DescendantsAndSelf()); + //TODO: This is pretty nasty, fix this + var contentTypeService = this as IContentTypeService; + if (contentTypeService != null) + { + //if a property was deleted or alias changed, then update all content of the current content type + // and all of it's desscendant doc types. + toUpdate.AddRange(((IContentType) contentType).DescendantsAndSelf(contentTypeService)); + } + else + { + var mediaTypeService = this as IMediaTypeService; + if (mediaTypeService != null) + { + //if a property was deleted or alias changed, then update all content of the current content type + // and all of it's desscendant doc types. + toUpdate.AddRange(((IMediaType) contentType).DescendantsAndSelf(mediaTypeService)); + } + else + { + var memberTypeService = this as IMemberTypeService; + if (memberTypeService != null) + { + //if a property was deleted or alias changed, then update all content of the current content type + // and all of it's desscendant doc types. + toUpdate.AddRange(((IMemberType)contentType).DescendantsAndSelf(memberTypeService)); + } + } + } + } } } @@ -550,7 +576,7 @@ namespace Umbraco.Core.Services uow.WriteLock(WriteLockIds); // all descendants are going to be deleted - var descendantsAndSelf = item.DescendantsAndSelf() + var descendantsAndSelf = item.DescendantsAndSelf(this) .ToArray(); // delete content @@ -587,7 +613,7 @@ namespace Umbraco.Core.Services uow.WriteLock(WriteLockIds); // all descendants are going to be deleted - var allDescendantsAndSelf = itemsA.SelectMany(xx => xx.DescendantsAndSelf()) + var allDescendantsAndSelf = itemsA.SelectMany(xx => xx.DescendantsAndSelf(this)) .Distinct() .ToArray(); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ac034c170b..823a77b2e5 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1191,7 +1191,6 @@ - diff --git a/src/Umbraco.Tests/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests/Cache/DistributedCache/DistributedCacheTests.cs index aa103d7eae..d4520e378c 100644 --- a/src/Umbraco.Tests/Cache/DistributedCache/DistributedCacheTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCache/DistributedCacheTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Cache.DistributedCache ServerMessengerResolver.Current = new ServerMessengerResolver( container, factory => new TestServerMessenger()); CacheRefreshersResolver.Current = new CacheRefreshersResolver( - new ActivatorServiceProvider(), Mock.Of(), () => new[] { typeof(TestCacheRefresher) }); + container, Mock.Of(), () => new[] { typeof(TestCacheRefresher) }); Resolution.Freeze(); } diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 9532101fb6..0c885e96f4 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -123,7 +123,7 @@ namespace Umbraco.Tests.Services var master = hierarchy.First(); //Act - var descendants = master.Descendants(); + var descendants = master.Descendants(ServiceContext.ContentTypeService); //Assert Assert.AreEqual(10, descendants.Count()); @@ -139,7 +139,7 @@ namespace Umbraco.Tests.Services var master = hierarchy.First(); //Act - var descendants = master.DescendantsAndSelf(); + var descendants = master.DescendantsAndSelf(ServiceContext.ContentTypeService); //Assert Assert.AreEqual(11, descendants.Count()); diff --git a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs index a95eef157d..73b254b594 100644 --- a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Web.Script.Serialization; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Models.Rdbms; - -using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.XmlPublishedCache; namespace Umbraco.Web.Cache @@ -24,6 +19,12 @@ namespace Umbraco.Web.Cache /// public sealed class ContentTypeCacheRefresher : JsonCacheRefresherBase { + private readonly ApplicationContext _applicationContext; + + public ContentTypeCacheRefresher(ApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } #region Static helpers @@ -45,7 +46,7 @@ namespace Umbraco.Web.Cache /// /// if the item was deleted /// - private static JsonPayload FromContentType(IContentTypeBase contentType, bool isDeleted = false) + private JsonPayload FromContentType(IContentTypeBase contentType, bool isDeleted = false) { var payload = new JsonPayload { @@ -57,10 +58,30 @@ namespace Umbraco.Web.Cache ? typeof(IContentType).Name : (contentType is IMediaType) ? typeof(IMediaType).Name - : typeof(IMemberType).Name, - DescendantPayloads = contentType.Descendants().Select(x => FromContentType(x)).ToArray(), + : typeof(IMemberType).Name, WasDeleted = isDeleted }; + + if (contentType is IContentType) + { + payload.DescendantPayloads = ((IContentType)contentType) + .Descendants(_applicationContext.Services.ContentTypeService) + .Select(x => FromContentType(x)).ToArray(); + } + else if (contentType is IMediaType) + { + payload.DescendantPayloads = ((IMediaType)contentType) + .Descendants(_applicationContext.Services.MediaTypeService) + .Select(x => FromContentType(x)).ToArray(); + } + else if (contentType is IMemberType) + { + payload.DescendantPayloads = ((IMemberType)contentType) + .Descendants(_applicationContext.Services.MemberTypeService) + .Select(x => FromContentType(x)).ToArray(); + } + + //here we need to check if the alias of the content type changed or if one of the properties was removed. var dirty = contentType as IRememberBeingDirty; if (dirty != null) @@ -78,7 +99,7 @@ namespace Umbraco.Web.Cache /// specify false if this is an update, otherwise true if it is a deletion /// /// - internal static string SerializeToJsonPayload(bool isDeleted, params IContentTypeBase[] contentTypes) + internal string SerializeToJsonPayload(bool isDeleted, params IContentTypeBase[] contentTypes) { var serializer = new JavaScriptSerializer(); var items = contentTypes.Select(x => FromContentType(x, isDeleted)).ToArray(); @@ -134,11 +155,11 @@ namespace Umbraco.Web.Cache ClearAllIsolatedCacheByEntityType(); //all property type cache - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.PropertyTypeCacheKey); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.PropertyTypeCacheKey); //all content type property cache - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.ContentTypePropertiesCacheKey); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.ContentTypePropertiesCacheKey); //all content type cache - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.ContentTypeCacheKey); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.ContentTypeCacheKey); //clear static object cache global::umbraco.cms.businesslogic.ContentType.RemoveAllDataTypeCache(); @@ -187,8 +208,8 @@ namespace Umbraco.Web.Cache { var needsContentRefresh = false; - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey); payloads.ForEach(payload => { @@ -265,18 +286,18 @@ namespace Umbraco.Web.Cache /// /// Return true if the alias of the content type changed /// - private static void ClearContentTypeCache(JsonPayload payload) + private void ClearContentTypeCache(JsonPayload payload) { //clears the cache for each property type associated with the content type foreach (var pid in payload.PropertyTypeIds) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.PropertyTypeCacheKey + pid); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.PropertyTypeCacheKey + pid); } //clears the cache associated with the Content type itself - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.ContentTypeCacheKey, payload.Id)); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.ContentTypeCacheKey, payload.Id)); //clears the cache associated with the content type properties collection - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ContentTypePropertiesCacheKey + payload.Id); + _applicationContext.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ContentTypePropertiesCacheKey + payload.Id); //clears the dictionary object cache of the legacy ContentType global::umbraco.cms.businesslogic.ContentType.RemoveFromDataTypeCache(payload.Alias); @@ -300,7 +321,7 @@ namespace Umbraco.Web.Cache ClearContentTypeCache( ids.Select( x => - ApplicationContext.Current.Services.ContentTypeService.Get(x) as IContentTypeBase) + _applicationContext.Services.ContentTypeService.Get(x) as IContentTypeBase) .WhereNotNull() .Select(x => FromContentType(x, isDeleted)) .ToArray()); diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 750872d8af..4182e0784b 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -304,13 +304,15 @@ namespace Umbraco.Web.Cache public static void RefreshContentTypeCache(this DistributedCache dc, IContentType contentType) { if (contentType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(false, contentType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(false, contentType)); } public static void RemoveContentTypeCache(this DistributedCache dc, IContentType contentType) { if (contentType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(true, contentType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(true, contentType)); } #endregion @@ -320,13 +322,15 @@ namespace Umbraco.Web.Cache public static void RefreshMediaTypeCache(this DistributedCache dc, IMediaType mediaType) { if (mediaType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(false, mediaType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(false, mediaType)); } public static void RemoveMediaTypeCache(this DistributedCache dc, IMediaType mediaType) { if (mediaType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(true, mediaType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(true, mediaType)); } #endregion @@ -336,13 +340,15 @@ namespace Umbraco.Web.Cache public static void RefreshMemberTypeCache(this DistributedCache dc, IMemberType memberType) { if (memberType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(false, memberType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(false, memberType)); } public static void RemoveMemberTypeCache(this DistributedCache dc, IMemberType memberType) { if (memberType == null) return; - dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, ContentTypeCacheRefresher.SerializeToJsonPayload(true, memberType)); + var contentTypeCacheRefresher = (ContentTypeCacheRefresher)CacheRefreshersResolver.Current.GetById(DistributedCache.ContentTypeCacheRefresherGuid); + dc.RefreshByJson(DistributedCache.ContentTypeCacheRefresherGuid, contentTypeCacheRefresher.SerializeToJsonPayload(true, memberType)); } #endregion