diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs index 7a7f26ebe9..8ba713090a 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using Umbraco.Cms.Core.Models.PublishedContent; @@ -57,9 +57,15 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters if ((propertyType.Alias != null && PropertiesToExclude.Contains(propertyType.Alias.ToLower(CultureInfo.InvariantCulture))) == false) { IPublishedContent content; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to get a published snapshot"); + } if (inter is int id) { - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(id); + + + content = publishedSnapshot.Content.GetById(id); if (content != null) return content; } @@ -68,7 +74,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var udi = inter as GuidUdi; if (udi == null) return null; - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udi.Guid); + content = publishedSnapshot.Content.GetById(udi.Guid); if (content != null && content.ContentType.ItemType == PublishedItemType.Content) return content; } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index f6523da44f..b37fc45789 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -73,11 +73,15 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters if (udis.Any()) { + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } foreach (var udi in udis) { var guidUdi = udi as GuidUdi; if (guidUdi == null) continue; - var item = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(guidUdi.Guid); + var item = publishedSnapshot.Media.GetById(guidUdi.Guid); if (item != null) mediaItems.Add(item); } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs index 2f5f7063c8..2e42681399 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs @@ -57,6 +57,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters if (_umbracoContextAccessor.UmbracoContext != null) { IPublishedContent member; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } if (source is int id) { IMember m = _memberService.GetById(id); @@ -64,7 +68,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters { return null; } - member = _publishedSnapshotAccessor.PublishedSnapshot?.Members.Get(m); + member = publishedSnapshot.Members.Get(m); if (member != null) { return member; @@ -81,7 +85,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters return null; } - member = _publishedSnapshotAccessor.PublishedSnapshot?.Members.Get(m); + member = publishedSnapshot.Members.Get(m); if (member != null) { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs index 1c97fccac4..a10ed36583 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs @@ -86,7 +86,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var multiNodeTreePicker = new List(); var objectType = UmbracoObjectTypes.Unknown; - + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } foreach (var udi in udis) { var guidUdi = udi as GuidUdi; @@ -96,10 +99,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters switch (udi.EntityType) { case Constants.UdiEntityType.Document: - multiNodeTreePickerItem = GetPublishedContent(udi, ref objectType, UmbracoObjectTypes.Document, id => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(guidUdi.Guid)); + multiNodeTreePickerItem = GetPublishedContent(udi, ref objectType, UmbracoObjectTypes.Document, id => publishedSnapshot.Content.GetById(guidUdi.Guid)); break; case Constants.UdiEntityType.Media: - multiNodeTreePickerItem = GetPublishedContent(udi, ref objectType, UmbracoObjectTypes.Media, id => _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(guidUdi.Guid)); + multiNodeTreePickerItem = GetPublishedContent(udi, ref objectType, UmbracoObjectTypes.Media, id => publishedSnapshot.Media.GetById(guidUdi.Guid)); break; case Constants.UdiEntityType.Member: multiNodeTreePickerItem = GetPublishedContent(udi, ref objectType, UmbracoObjectTypes.Member, id => @@ -109,7 +112,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters { return null; } - IPublishedContent member = _publishedSnapshotAccessor.PublishedSnapshot.Members.Get(m); + IPublishedContent member = publishedSnapshot.Members.Get(m); return member; }); break; diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs index 500507988c..60abd21f4c 100644 --- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs +++ b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs @@ -1,10 +1,10 @@ -namespace Umbraco.Cms.Core.PublishedCache +namespace Umbraco.Cms.Core.PublishedCache { /// /// Provides access to the "current" . /// public interface IPublishedSnapshotAccessor { - IPublishedSnapshot PublishedSnapshot { get; set; } + bool TryGetPublishedSnapshot(out IPublishedSnapshot publishedSnapshot); } } diff --git a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs index 0632e50b88..b3af8a40fa 100644 --- a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs +++ b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors; @@ -112,8 +112,10 @@ namespace Umbraco.Cms.Core.PublishedCache // elements cache (if we don't want to pollute the elements cache with short-lived // data) depending on settings // for members, always cache in the snapshot cache - never pollute elements cache - var publishedSnapshot = _publishedSnapshotAccessor?.PublishedSnapshot; - if (publishedSnapshot == null) return null; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + return null; + } return (IsPreviewing == false || FullCacheWhenPreviewing) && IsMember == false ? publishedSnapshot.ElementsCache : publishedSnapshot.SnapshotCache; @@ -138,8 +140,12 @@ namespace Umbraco.Cms.Core.PublishedCache cacheValues = (CacheValues) snapshotCache?.Get(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); break; case PropertyCacheLevel.Snapshot: + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } // cache within the snapshot cache - var facadeCache = _publishedSnapshotAccessor?.PublishedSnapshot?.SnapshotCache; + var facadeCache = publishedSnapshot.SnapshotCache; cacheValues = (CacheValues) facadeCache?.Get(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); break; default: diff --git a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs b/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs index 4a8c9e6346..8ab6fab7d9 100644 --- a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs +++ b/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs @@ -27,5 +27,12 @@ namespace Umbraco.Cms.Core.PublishedCache set => throw new NotSupportedException(); // not ok to set } + + public bool TryGetPublishedSnapshot(out IPublishedSnapshot publishedSnapshot) + { + publishedSnapshot = _umbracoContextAccessor.UmbracoContext?.PublishedSnapshot; + + return publishedSnapshot is not null; + } } } diff --git a/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs b/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs index f449c40d43..68a15580e4 100644 --- a/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs +++ b/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs @@ -1,7 +1,9 @@ +using Umbraco.Cms.Infrastructure; + namespace Umbraco.Cms.Core { public interface IPublishedContentQueryAccessor { - IPublishedContentQuery PublishedContentQuery { get;} + bool TryGetValue(out IPublishedContentQuery publishedContentQuery); } } diff --git a/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs b/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs index 82cf52a131..d4800ef188 100644 --- a/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs +++ b/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs @@ -32,15 +32,18 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder public static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor, PublishedItemType itemType, string alias) { - var facade = publishedSnapshotAccessor.PublishedSnapshot; + if (!publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } switch (itemType) { case PublishedItemType.Content: - return facade.Content.GetContentType(alias); + return publishedSnapshot.Content.GetContentType(alias); case PublishedItemType.Media: - return facade.Media.GetContentType(alias); + return publishedSnapshot.Media.GetContentType(alias); case PublishedItemType.Member: - return facade.Members.GetContentType(alias); + return publishedSnapshot.Members.GetContentType(alias); default: throw new ArgumentOutOfRangeException(nameof(itemType)); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs index 11d49b5bf9..333722ee45 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -95,13 +95,16 @@ namespace Umbraco.Cms.Core.PropertyEditors { continue; } - + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } if (entity is IDocumentEntitySlim documentEntity) { icon = documentEntity.ContentTypeIcon; published = culture == null ? documentEntity.Published : documentEntity.PublishedCultures.Contains(culture); udi = new GuidUdi(Constants.UdiEntityType.Document, documentEntity.Key); - url = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#"; + url = publishedSnapshot.Content.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#"; trashed = documentEntity.Trashed; } else if(entity is IContentEntitySlim contentEntity) @@ -109,7 +112,7 @@ namespace Umbraco.Cms.Core.PropertyEditors icon = contentEntity.ContentTypeIcon; published = !contentEntity.Trashed; udi = new GuidUdi(Constants.UdiEntityType.Media, contentEntity.Key); - url = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#"; + url = publishedSnapshot.Media.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#"; trashed = contentEntity.Trashed; } else diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs index 76cfb10943..a8c85a5924 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -26,8 +26,12 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters BlockItemData data, PropertyCacheLevel referenceCacheLevel, bool preview) { + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } // hack! we need to cast, we have no choice beacuse we cannot make breaking changes. - var publishedContentCache = _publishedSnapshotAccessor.PublishedSnapshot.Content; + var publishedContentCache = publishedSnapshot.Content; // only convert element types - content types will cause an exception when PublishedModelFactory creates the model var publishedContentType = publishedContentCache.GetContentType(data.ContentTypeKey); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs index 51bf3c477c..07412adbf4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Umbraco.Cms.Core.Models.PublishedContent; @@ -63,10 +63,13 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var mediaItems = new List(); var dtos = MediaPicker3PropertyEditor.MediaPicker3PropertyValueEditor.Deserialize(_jsonSerializer, inter); var configuration = propertyType.DataType.ConfigurationAs(); - + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } foreach (var dto in dtos) { - var mediaItem = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(preview, dto.MediaKey); + var mediaItem = publishedSnapshot.Media.GetById(preview, dto.MediaKey); if (mediaItem != null) { var localCrops = new ImageCropperValue diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs index 947b1fc3e4..9d79ec16fa 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs @@ -58,7 +58,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var links = new List(); var dtos = _jsonSerializer.Deserialize>(inter.ToString()); - + if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } foreach (var dto in dtos) { var type = LinkType.External; @@ -71,8 +74,8 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters : LinkType.Content; var content = type == LinkType.Media ? - _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(preview, dto.Udi.Guid) : - _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(preview, dto.Udi.Guid); + publishedSnapshot.Media.GetById(preview, dto.Udi.Guid) : + publishedSnapshot.Content.GetById(preview, dto.Udi.Guid); if (content == null || content.ContentType.ItemType == PublishedItemType.Element) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs index e46b830af0..89fa1d5d32 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -46,9 +46,12 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var elementTypeAlias = sourceObject[NestedContentPropertyEditor.ContentTypeAliasPropertyKey]?.ToObject(); if (string.IsNullOrEmpty(elementTypeAlias)) return null; - + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } // only convert element types - content types will cause an exception when PublishedModelFactory creates the model - var publishedContentType = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetContentType(elementTypeAlias); + var publishedContentType = publishedSnapshot.Content.GetContentType(elementTypeAlias); if (publishedContentType == null || publishedContentType.IsElement == false) return null; diff --git a/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs b/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs index 4c19292afa..6ca23133db 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Infrastructure; namespace Umbraco.Cms.Core { @@ -7,11 +8,13 @@ namespace Umbraco.Cms.Core { private readonly IServiceProvider _serviceProvider; - public PublishedContentQueryAccessor(IServiceProvider serviceProvider) + public PublishedContentQueryAccessor(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; + public bool TryGetValue(out IPublishedContentQuery publishedContentQuery) { - _serviceProvider = serviceProvider; + publishedContentQuery = _serviceProvider.GetRequiredService(); + + return publishedContentQuery is not null; } - public IPublishedContentQuery PublishedContentQuery => _serviceProvider.GetRequiredService(); } } diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs index 7b3b3f86ed..34f8f188c3 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs @@ -87,7 +87,11 @@ namespace Umbraco.Cms.Core.Routing private void StoreOldRoute(IContent entity, OldRoutesDictionary oldRoutes) { - var contentCache = _publishedSnapshotAccessor.PublishedSnapshot.Content; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } + var contentCache = publishedSnapshot.Content; var entityContent = contentCache.GetById(entity.Id); if (entityContent == null) return; @@ -112,7 +116,11 @@ namespace Umbraco.Cms.Core.Routing private void CreateRedirects(OldRoutesDictionary oldRoutes) { - var contentCache = _publishedSnapshotAccessor.PublishedSnapshot.Content; + if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } + var contentCache = publishedSnapshot.Content; foreach (var oldRoute in oldRoutes) { diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index fe12a349f8..6366bbeb27 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -624,7 +624,11 @@ namespace Umbraco.Cms.Core.Security { return null; } - return _publishedSnapshotAccessor.PublishedSnapshot?.Members.Get(member); + if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } + return publishedSnapshot.Members.Get(member); } private enum MemberDataChangeType diff --git a/src/Umbraco.PublishedCache.NuCache/Property.cs b/src/Umbraco.PublishedCache.NuCache/Property.cs index 2b5655b314..dc00b241f7 100644 --- a/src/Umbraco.PublishedCache.NuCache/Property.cs +++ b/src/Umbraco.PublishedCache.NuCache/Property.cs @@ -125,7 +125,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel) { CacheValues cacheValues; - PublishedSnapshot publishedSnapshot; + IPublishedSnapshot publishedSnapshot; IAppCache cache; switch (cacheLevel) { @@ -142,7 +142,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache // elements cache (if we don't want to pollute the elements cache with short-lived // data) depending on settings // for members, always cache in the snapshot cache - never pollute elements cache - publishedSnapshot = (PublishedSnapshot) _publishedSnapshotAccessor.PublishedSnapshot; + if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } cache = publishedSnapshot == null ? null : ((_isPreviewing == false || PublishedSnapshotService.FullCacheWhenPreviewing) && (_isMember == false) @@ -152,7 +155,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache break; case PropertyCacheLevel.Snapshot: // cache within the snapshot cache - publishedSnapshot = (PublishedSnapshot) _publishedSnapshotAccessor.PublishedSnapshot; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } cache = publishedSnapshot?.SnapshotCache; cacheValues = GetCacheValues(cache); break; diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs b/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs index e6552b7df3..7cefbe06d9 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs @@ -238,7 +238,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache get { var getById = GetGetterById(); - var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } return getById(publishedSnapshot, IsPreviewing, ParentId); } } @@ -249,7 +252,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache get { var getById = GetGetterById(); - var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } var id = _contentNode.FirstChildContentId; while (id > 0) @@ -316,7 +322,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache // beware what you use that one for - you don't want to cache its result private IAppCache GetAppropriateCache() { - var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } var cache = publishedSnapshot == null ? null : ((IsPreviewing == false || PublishedSnapshotService.FullCacheWhenPreviewing) && (ContentType.ItemType != PublishedItemType.Member) @@ -327,7 +336,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache private IAppCache GetCurrentSnapshotCache() { - var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot; + if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } return publishedSnapshot?.SnapshotCache; } diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index f73b5b505e..e68278a8d6 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -117,7 +117,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache _publishedModelFactory = publishedModelFactory; } - protected PublishedSnapshot CurrentPublishedSnapshot => (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot; + protected PublishedSnapshot CurrentPublishedSnapshot { get { _publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot); return (PublishedSnapshot)publishedSnapshot; } } // NOTE: These aren't used within this object but are made available internally to improve the IdKey lookup performance // when nucache is enabled. diff --git a/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs b/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs index cab51ae91b..400a79292e 100644 --- a/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs +++ b/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs @@ -7,6 +7,10 @@ namespace Umbraco.Cms.Tests.Common { public class TestPublishedSnapshotAccessor : IPublishedSnapshotAccessor { - public IPublishedSnapshot PublishedSnapshot { get; set; } + public bool TryGetPublishedSnapshot(out IPublishedSnapshot publishedSnapshot) + { + publishedSnapshot = null; + return false; + } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs index b4a6d288d1..084bf03370 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors contentCache.Setup(x => x.GetContentType(_settingKey1)).Returns(test3ContentType); contentCache.Setup(x => x.GetContentType(_settingKey2)).Returns(test4ContentType); IPublishedSnapshot publishedSnapshot = Mock.Of(x => x.Content == contentCache.Object); - IPublishedSnapshotAccessor publishedSnapshotAccessor = Mock.Of(x => x.PublishedSnapshot == publishedSnapshot); + IPublishedSnapshotAccessor publishedSnapshotAccessor = Mock.Of(x => x.TryGetPublishedSnapshot(out publishedSnapshot)); return publishedSnapshotAccessor; } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs index 2dfc925502..d1f90bd849 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs @@ -56,7 +56,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors var publishedSnapshotMock = new Mock(); publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); var publishedSnapshotAccessorMock = new Mock(); - publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); + var localPublishedSnapshot = publishedSnapshotMock.Object; + publishedSnapshotAccessorMock.Setup(x => x.TryGetPublishedSnapshot(out localPublishedSnapshot)).Returns(true); register.AddTransient(f => publishedSnapshotAccessorMock.Object); IServiceProvider registerFactory = composition.CreateServiceProvider(); @@ -203,9 +204,15 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, - bool preview) => ((int[])inter).Select(x => - (PublishedSnapshotTestObjects.TestContentModel1)_publishedSnapshotAccessor.PublishedSnapshot.Content + bool preview) { + if(!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } + return ((int[])inter).Select(x => + (PublishedSnapshotTestObjects.TestContentModel1)publishedSnapshot.Content .GetById(x)).ToArray(); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs index 76a536c2e0..b625cb120e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -104,7 +104,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published var publishedSnapshotMock = new Mock(); publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); var publishedSnapshotAccessorMock = new Mock(); - publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); + var localPublishedSnapshot = publishedSnapshotMock.Object; + publishedSnapshotAccessorMock.Setup(x => x.TryGetPublishedSnapshot(out localPublishedSnapshot)).Returns(true); IPublishedSnapshotAccessor publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; var converters = new PropertyValueConverterCollection(() => new IPropertyValueConverter[] @@ -170,7 +171,13 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published => int.TryParse(source as string, out int i) ? i : -1; public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById((int)inter); + { + if(!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) + { + throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot"); + } + return publishedSnapshot.Content.GetById((int)inter); + } public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) => ((int)inter).ToString(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index 5f5de0cf4e..fdc50484d2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -122,9 +122,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published var publishedSnapshotAccessor = new Mock(); // mocked published snapshot accessor returns a facade + var localPublishedSnapshot = publishedSnapshot.Object; publishedSnapshotAccessor - .Setup(x => x.PublishedSnapshot) - .Returns(publishedSnapshot.Object); + .Setup(x => x.TryGetPublishedSnapshot(out localPublishedSnapshot)) + .Returns(true); var converters = new PropertyValueConverterCollection(() => new IPropertyValueConverter[] { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs index a57355afd9..0f0ad8f2f6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -148,7 +148,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published publishedSnapshot.Setup(x => x.ElementsCache).Returns(elementsCache); var publishedSnapshotAccessor = new Mock(); - publishedSnapshotAccessor.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshot.Object); + var localPublishedSnapshot = publishedSnapshot.Object; + publishedSnapshotAccessor.Setup(x => x.TryGetPublishedSnapshot(out localPublishedSnapshot)).Returns(true); // pretend we're creating this set as a value for a property // referenceCacheLevel is the cache level for this fictious property diff --git a/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs b/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs index 9671468631..f81a912df0 100644 --- a/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs +++ b/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs @@ -2,6 +2,7 @@ namespace Umbraco.Cms.Web.Common { public interface IUmbracoHelperAccessor { - UmbracoHelper UmbracoHelper { get;} + bool TryGetUmbracoHelper(out UmbracoHelper umbracoHelper); + } } diff --git a/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs b/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs index 765aca792a..f9cf0d432f 100644 --- a/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs +++ b/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs @@ -12,11 +12,13 @@ namespace Umbraco.Cms.Web.Common { private readonly IHttpContextAccessor _httpContextAccessor; - public UmbracoHelperAccessor(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - public UmbracoHelper UmbracoHelper => _httpContextAccessor.HttpContext.RequestServices.GetRequiredService(); + public UmbracoHelperAccessor(IHttpContextAccessor httpContextAccessor) => _httpContextAccessor = httpContextAccessor; + public bool TryGetUmbracoHelper(out UmbracoHelper umbracoHelper) + { + umbracoHelper = _httpContextAccessor.HttpContext.RequestServices.GetService(); + + return umbracoHelper is not null; + } } }