V15: Remove Nucache (#17166)

* Remove nucache reference from Web.Common

* Get tests building-ish

* Move ReservedFieldNamesService to the right project

* Remove IPublishedSnapshotStatus

* Added functionality to the INavigationQueryService to get root keys

* Fixed issue with navigation

* Remove IPublishedSnapshot from UmbracoContext

* Begin removing usage of IPublishedSnapshot from PublishedContentExtensions

* Fix PublishedContentExtensions.cs

* Don't use snapshots in delivery media api

* Use IPublishedMediaCache in QueryMediaApiController

* Remove more usages of IPublishedSnapshotAccessor

* Comment out tests

* Remove more usages of PublishedSnapshotAccessor

* Remove PublishedSnapshot from property

* Fixed test build

* Fix errors

* Fix some tests

* Delete NuCache 🎉

* Implement DatabaseCacheRebuilder

* Remove usage of IPublishedSnapshotService

* Remove IPublishedSnapshotService

* Remove TestPublishedSnapshotAccessor and make tests build

* Don't test Snapshot cachelevel

It's no longer supported

* Fix BlockEditorConverter

Element != Element document type

* Remember to set cachemanager

* Fix RichTextParserTests

* Implement TryGetLevel on INavigationQueryService

* Fake level and obsolete it in PublishedContent

* Remove ChildrenForAllCultures

* Hack Path property on PublishedContent

* Remove usages of IPublishedSnapshot in tests

* More ConvertersTests

* Add hybrid cache to integration tests

We can actually do this now because we no longer save files on disk

* Rename IPublishedSnapshotRebuilder to ICacheRebuilder

* Comment out tests

* V15: Replacing the usages of Parent (navigation data) from IPublishedContent (#17125)

* Fix .Parent references in PublishedContentExtensions

* Add missing methods to FriendlyPublishedContentExtensions (ones that you were able to call on the content directly as they now require extra params)

* Fix references from the extension methods

* Fix dependencies in tests

* Replace IPublishedSnapshotAccessor with the content cache in tests

* Resolving more .Parent references

* Fix unit tests

* Obsolete and use extension methods

* Remove private method and use extension instead

* Moving code around

* Fix tests

* Fix more references

* Cleanup

* Fix more usages

* Resolve merge conflict

* Fix tests

* Cleanup

* Fix more tests

* Fixed unit tests

* Cleanup

* Replace last usages

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>

* Remove usage of IPublishedSnapshotAccessor from IRequestItemProvider

* Post merge fixup

* Remo IPublishedSnapshot

* Add HasAny to IDocumentUrlService

* Fix TextBuilder

* Fix modelsbuilder tests

* Use explicit types

* Implement GetByContentType

* Support element types in PublishedContentTypeCache

* Run enlistments before publishing notifications

* Fix elements cache refreshing

* Implement GetByUdi

* Implement GetAtRoot

* Implement GetByRoute

* Reimplement GetRouteById

* Fix blocks unit tests

* Initialize domain cache on boot

* Only return routes with domains on non default lanauges

* V15: Replacing the usages of `Children` (navigation data) from `IPublishedContent` (#17159)

* Update params in PublishedContentExtensions to the general interfaces for the published cache and navigation service, so that we can use the extension methods on both documents and media

* Introduce GetParent() which uses the right services

* Fix obsolete message on .Parent

* Obsolete .Children

* Fix usages of Children for ApiMediaQueryService

* Fix usage in internal

* Fix usages in views

* Fix indentation

* Fix issue with delete language

* Update nuget pacakges

* Clear elements cache when content is deleted

instead of trying to update it

* Reset publishedModelFactory

* Fixed publishing

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com>
Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
Mole
2024-10-01 15:03:02 +02:00
committed by GitHub
parent 7ca96423f8
commit 1258962429
270 changed files with 12051 additions and 21515 deletions

View File

@@ -0,0 +1,16 @@
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.HybridCache.Persistence;
namespace Umbraco.Cms.Infrastructure.HybridCache;
internal class DatabaseCacheRebuilder : IDatabaseCacheRebuilder
{
private readonly IDatabaseCacheRepository _databaseCacheRepository;
public DatabaseCacheRebuilder(IDatabaseCacheRepository databaseCacheRepository)
{
_databaseCacheRepository = databaseCacheRepository;
}
public void Rebuild() => _databaseCacheRepository.Rebuild();
}

View File

@@ -44,6 +44,7 @@ public static class UmbracoBuilderExtensions
builder.Services.AddSingleton<IPublishedContentFactory, PublishedContentFactory>();
builder.Services.AddSingleton<ICacheNodeFactory, CacheNodeFactory>();
builder.Services.AddSingleton<ICacheManager, CacheManager>();
builder.Services.AddSingleton<IDatabaseCacheRebuilder, DatabaseCacheRebuilder>();
builder.Services.AddSingleton<IContentCacheDataSerializerFactory>(s =>
{
IOptions<NuCacheSettings> options = s.GetRequiredService<IOptions<NuCacheSettings>>();
@@ -62,8 +63,9 @@ public static class UmbracoBuilderExtensions
builder.AddNotificationAsyncHandler<ContentDeletedNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<MediaRefreshNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<MediaDeletedNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<UmbracoApplicationStartedNotification, SeedingNotificationHandler>();
builder.AddNotificationAsyncHandler<ContentTypeRefreshedNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<ContentTypeDeletedNotification, CacheRefreshingNotificationHandler>();
builder.AddNotificationAsyncHandler<UmbracoApplicationStartedNotification, SeedingNotificationHandler>();
builder.AddCacheSeeding();
return builder;
}

View File

@@ -1,7 +1,12 @@
using Umbraco.Cms.Core;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Infrastructure.HybridCache.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.HybridCache;
@@ -34,31 +39,86 @@ public sealed class DocumentCache : IPublishedContentCache
public IPublishedContentType? GetContentType(string alias) => _publishedContentTypeCache.Get(PublishedItemType.Content, alias);
public IPublishedContentType? GetContentType(Guid key) => _publishedContentTypeCache.Get(PublishedItemType.Content, key);
// FIXME: These need to be refactored when removing nucache
// Thats the time where we can change the IPublishedContentCache interface.
// TODO: These are all obsolete and should be removed
public IPublishedContent? GetById(bool preview, Udi contentId) => throw new NotImplementedException();
[Obsolete("Scheduled for removal in v17")]
public IPublishedContent? GetById(bool preview, Udi contentId)
{
if(contentId is not GuidUdi guidUdi)
{
throw new NotSupportedException("Only GuidUdi is supported");
}
public IPublishedContent? GetById(Udi contentId) => throw new NotImplementedException();
return GetById(preview, guidUdi.Guid);
}
public IEnumerable<IPublishedContent> GetAtRoot(bool preview, string? culture = null) => throw new NotImplementedException();
[Obsolete("Scheduled for removal in v17")]
public IPublishedContent? GetById(Udi contentId)
{
if(contentId is not GuidUdi guidUdi)
{
throw new NotSupportedException("Only GuidUdi is supported");
}
public IEnumerable<IPublishedContent> GetAtRoot(string? culture = null) => throw new NotImplementedException();
return GetById(guidUdi.Guid);
}
public bool HasContent(bool preview) => throw new NotImplementedException();
[Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
public IEnumerable<IPublishedContent> GetAtRoot(bool preview, string? culture = null)
{
IDocumentNavigationQueryService navigationService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
navigationService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
public bool HasContent() => throw new NotImplementedException();
IEnumerable<IPublishedContent> rootContent = rootKeys.Select(key => GetById(preview, key)).WhereNotNull();
return culture is null ? rootContent : rootContent.Where(x => x.IsInvariantOrHasCulture(culture));
}
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType) => throw new NotImplementedException();
[Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
public IEnumerable<IPublishedContent> GetAtRoot(string? culture = null)
{
IDocumentNavigationQueryService navigationService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
navigationService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
public IPublishedContent? GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string? culture = null) => throw new NotImplementedException();
IEnumerable<IPublishedContent> rootContent = rootKeys.Select(key => GetById(key)).WhereNotNull();
return culture is null ? rootContent : rootContent.Where(x => x.IsInvariantOrHasCulture(culture));
}
public IPublishedContent? GetByRoute(string route, bool? hideTopLevelNode = null, string? culture = null) => throw new NotImplementedException();
[Obsolete("Scheduled for removal in v17")]
public bool HasContent(bool preview) => HasContent();
public string? GetRouteById(bool preview, int contentId, string? culture = null) => throw new NotImplementedException();
[Obsolete("Scheduled for removal in v17")]
public bool HasContent() => StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>().HasAny();
public string? GetRouteById(int contentId, string? culture = null) => throw new NotImplementedException();
[Obsolete]
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)
=> _documentCacheService.GetByContentType(contentType);
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
public IPublishedContent? GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string? culture = null)
{
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
Guid? key = documentUrlService.GetDocumentKeyByRoute(route, culture, null, preview);
return key is not null ? GetById(preview, key.Value) : null;
}
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
public IPublishedContent? GetByRoute(string route, bool? hideTopLevelNode = null, string? culture = null)
{
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
Guid? key = documentUrlService.GetDocumentKeyByRoute(route, culture, null, false);
return key is not null ? GetById(key.Value) : null;
}
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
public string? GetRouteById(bool preview, int contentId, string? culture = null)
{
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
IPublishedContent? content = GetById(preview, contentId);
return content is not null ? documentUrlService.GetLegacyRouteFormat(content.Key, culture, preview) : null;
}
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
public string? GetRouteById(int contentId, string? culture = null) => GetRouteById(false, contentId, culture);
}

View File

@@ -1,4 +1,6 @@
using Umbraco.Cms.Core.Models;
using StackExchange.Profiling.Internal;
using Umbraco.Cms.Core.Media.EmbedProviders;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
@@ -17,7 +19,14 @@ internal class CacheNodeFactory : ICacheNodeFactory
public ContentCacheNode ToContentCacheNode(IContent content, bool preview)
{
ContentData contentData = GetContentData(content, !preview, preview ? content.TemplateId : content.PublishTemplateId);
ContentData contentData = GetContentData(
content,
GetPublishedValue(content, preview),
GetTemplateId(content, preview),
content.PublishCultureInfos!.Values.Select(x=>x.Culture).ToHashSet()
);
return new ContentCacheNode
{
Id = content.Id,
@@ -31,9 +40,39 @@ internal class CacheNodeFactory : ICacheNodeFactory
};
}
private bool GetPublishedValue(IContent content, bool preview)
{
switch (content.PublishedState)
{
case PublishedState.Published:
return preview;
case PublishedState.Publishing:
return preview is false || content.Published; // The type changes after this operation
case PublishedState.Unpublished:
case PublishedState.Unpublishing:
default:
return false;
}
}
private int? GetTemplateId(IContent content, bool preview)
{
switch (content.PublishedState)
{
case PublishedState.Published:
return preview ? content.TemplateId : content.PublishTemplateId;
case PublishedState.Publishing:
return content.TemplateId;// The type changes after this operation is we need to read the draft values
case PublishedState.Unpublished:
case PublishedState.Unpublishing:
default:
return null;
}
}
public ContentCacheNode ToContentCacheNode(IMedia media)
{
ContentData contentData = GetContentData(media, false, null);
ContentData contentData = GetContentData(media, false, null, new HashSet<string>());
return new ContentCacheNode
{
Id = media.Id,
@@ -47,7 +86,7 @@ internal class CacheNodeFactory : ICacheNodeFactory
};
}
private ContentData GetContentData(IContentBase content, bool published, int? templateId)
private ContentData GetContentData(IContentBase content, bool published, int? templateId, ISet<string> publishedCultures)
{
var propertyData = new Dictionary<string, PropertyData[]>();
foreach (IProperty prop in content.Properties)
@@ -62,7 +101,15 @@ internal class CacheNodeFactory : ICacheNodeFactory
}
// note: at service level, invariant is 'null', but here invariant becomes 'string.Empty'
var value = published ? pvalue.PublishedValue : pvalue.EditedValue;
if (published && (string.IsNullOrEmpty(pvalue.Culture) is false && publishedCultures.Contains(pvalue.Culture) is false))
{
continue;
}
var value = published
? pvalue.PublishedValue
: pvalue.EditedValue;
if (value != null)
{
pdatas.Add(new PropertyData

View File

@@ -1,4 +1,5 @@
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Models.PublishedContent;
@@ -17,7 +18,8 @@ internal sealed class CacheRefreshingNotificationHandler :
INotificationAsyncHandler<ContentDeletedNotification>,
INotificationAsyncHandler<MediaRefreshNotification>,
INotificationAsyncHandler<MediaDeletedNotification>,
INotificationAsyncHandler<ContentTypeRefreshedNotification>
INotificationAsyncHandler<ContentTypeRefreshedNotification>,
INotificationAsyncHandler<ContentTypeDeletedNotification>
{
private readonly IDocumentCacheService _documentCacheService;
private readonly IMediaCacheService _mediaCacheService;
@@ -50,7 +52,7 @@ internal sealed class CacheRefreshingNotificationHandler :
{
foreach (IContent deletedEntity in notification.DeletedEntities)
{
await RefreshElementsCacheAsync(deletedEntity);
RemoveFromElementsCache(deletedEntity);
await _documentCacheService.DeleteItemAsync(deletedEntity);
}
}
@@ -65,7 +67,7 @@ internal sealed class CacheRefreshingNotificationHandler :
{
foreach (IMedia deletedEntity in notification.DeletedEntities)
{
await RefreshElementsCacheAsync(deletedEntity);
RemoveFromElementsCache(deletedEntity);
await _mediaCacheService.DeleteItemAsync(deletedEntity);
}
}
@@ -76,6 +78,8 @@ internal sealed class CacheRefreshingNotificationHandler :
IEnumerable<IRelation> childRelations = _relationService.GetByChild(content);
var ids = parentRelations.Select(x => x.ChildId).Concat(childRelations.Select(x => x.ParentId)).ToHashSet();
// We need to add ourselves to the list of ids to clear
ids.Add(content.Id);
foreach (var id in ids)
{
if (await _documentCacheService.HasContentByIdAsync(id) is false)
@@ -92,20 +96,33 @@ internal sealed class CacheRefreshingNotificationHandler :
foreach (IPublishedProperty publishedProperty in publishedContent.Properties)
{
var property = (PublishedProperty) publishedProperty;
if (property.ReferenceCacheLevel != PropertyCacheLevel.Elements)
if (property.ReferenceCacheLevel is PropertyCacheLevel.Elements
|| property.PropertyType.DeliveryApiCacheLevel is PropertyCacheLevel.Elements
|| property.PropertyType.DeliveryApiCacheLevelForExpansion is PropertyCacheLevel.Elements)
{
continue;
_elementsCache.ClearByKey(property.ValuesCacheKey);
}
_elementsCache.ClearByKey(property.ValuesCacheKey);
}
}
}
private void RemoveFromElementsCache(IUmbracoEntity content)
{
// ClearByKey clears by "startsWith" so we'll clear by the cachekey prefix + contentKey
// This will clear any and all properties for this content item, this is important because
// we cannot resolve the PublishedContent for this entity since it and its content type is deleted.
_elementsCache.ClearByKey(GetContentWideCacheKey(content.Key, true));
_elementsCache.ClearByKey(GetContentWideCacheKey(content.Key, false));
}
private string GetContentWideCacheKey(Guid contentKey, bool isPreviewing) => isPreviewing
? CacheKeys.PreviewPropertyCacheKeyPrefix + contentKey
: CacheKeys.PropertyCacheKeyPrefix + contentKey;
public Task HandleAsync(ContentTypeRefreshedNotification notification, CancellationToken cancellationToken)
{
const ContentTypeChangeTypes types // only for those that have been refreshed
= ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther | ContentTypeChangeTypes.Remove;
= ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther;
var contentTypeIds = notification.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id)
.ToArray();
@@ -121,4 +138,14 @@ internal sealed class CacheRefreshingNotificationHandler :
return Task.CompletedTask;
}
public Task HandleAsync(ContentTypeDeletedNotification notification, CancellationToken cancellationToken)
{
foreach (IContentType deleted in notification.DeletedEntities)
{
_publishedContentTypeCache.ClearContentType(deleted.Id);
}
return Task.CompletedTask;
}
}

View File

@@ -1,11 +1,13 @@
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Exceptions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.HybridCache;
@@ -77,8 +79,8 @@ internal class PublishedContent : PublishedContentBase
{
get
{
var documentNavigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
var idKeyMap = StaticServiceProvider.Instance.GetRequiredService<IIdKeyMap>();
IDocumentNavigationQueryService documentNavigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
IIdKeyMap idKeyMap = StaticServiceProvider.Instance.GetRequiredService<IIdKeyMap>();
if (documentNavigationQueryService.TryGetAncestorsOrSelfKeys(Key, out var ancestorsOrSelfKeys))
@@ -86,7 +88,7 @@ internal class PublishedContent : PublishedContentBase
var sb = new StringBuilder("-1");
foreach (Guid ancestorsOrSelfKey in ancestorsOrSelfKeys.Reverse())
{
var idAttempt = idKeyMap.GetIdForKey(ancestorsOrSelfKey, GetObjectType());
Attempt<int> idAttempt = idKeyMap.GetIdForKey(ancestorsOrSelfKey, GetObjectType());
if (idAttempt.Success)
{
sb.AppendFormat(",{0}", idAttempt.Result);
@@ -130,12 +132,31 @@ internal class PublishedContent : PublishedContentBase
// Needed for publishedProperty
internal IVariationContextAccessor VariationContextAccessor { get; }
public override int Level { get; } = 0;
[Obsolete("Use the INavigationQueryService instead, scheduled for removal in v17")]
public override int Level
{
get
{
INavigationQueryService? navigationQueryService = null;
switch (_contentNode.ContentType.ItemType)
{
case PublishedItemType.Content:
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
break;
case PublishedItemType.Media:
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
break;
default:
throw new NotImplementedException("Level is not implemented for " + _contentNode.ContentType.ItemType);
}
public override IEnumerable<IPublishedContent> ChildrenForAllCultures { get; } = Enumerable.Empty<IPublishedContent>();
public override IPublishedContent? Parent { get; } = null!;
navigationQueryService.TryGetLevel(Key, out int level);
return level;
}
}
[Obsolete("Please use TryGetParentKey() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
public override IPublishedContent? Parent => GetParent();
/// <inheritdoc />
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures
@@ -238,4 +259,26 @@ internal class PublishedContent : PublishedContentBase
// = depends on the culture
return _contentNode.HasPublishedCulture(culture);
}
private IPublishedContent? GetParent()
{
INavigationQueryService? navigationQueryService;
IPublishedCache? publishedCache;
switch (ContentType.ItemType)
{
case PublishedItemType.Content:
publishedCache = StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>();
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
break;
case PublishedItemType.Media:
publishedCache = StaticServiceProvider.Instance.GetRequiredService<IPublishedMediaCache>();
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
break;
default:
throw new NotImplementedException("Level is not implemented for " + ContentType.ItemType);
}
return this.Parent<IPublishedContent>(publishedCache, navigationQueryService);
}
}

View File

@@ -80,10 +80,10 @@ internal class PublishedProperty : PublishedPropertyBase
{
if (previewing)
{
return "Cache.Property.CacheValues[D:" + contentUid + ":" + typeAlias + "]";
return CacheKeys.PreviewPropertyCacheKeyPrefix + contentUid + ":" + typeAlias + "]";
}
return "Cache.Property.CacheValues[P:" + contentUid + ":" + typeAlias + "]";
return CacheKeys.PropertyCacheKeyPrefix + contentUid + ":" + typeAlias + "]";
}
// determines whether a property has value

View File

@@ -1,6 +1,4 @@
using System.Diagnostics;
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
@@ -96,6 +94,17 @@ internal sealed class DocumentCacheService : IDocumentCacheService
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, preview).CreateModel(_publishedModelFactory);;
}
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope();
IEnumerable<ContentCacheNode> nodes = _databaseCacheRepository.GetContentByContentTypeKey([contentType.Key]);
scope.Complete();
return nodes
.Select(x => _publishedContentFactory.ToIPublishedContent(x, x.IsDraft).CreateModel(_publishedModelFactory))
.WhereNotNull();
}
public async Task SeedAsync(CancellationToken cancellationToken)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope();

View File

@@ -17,6 +17,7 @@ public class DomainCacheService : IDomainCacheService
private readonly IDomainService _domainService;
private readonly ICoreScopeProvider _coreScopeProvider;
private readonly ConcurrentDictionary<int, Domain> _domains;
private bool _initialized = false;
public DomainCacheService(IDomainService domainService, ICoreScopeProvider coreScopeProvider)
{
@@ -27,14 +28,26 @@ public class DomainCacheService : IDomainCacheService
public IEnumerable<Domain> GetAll(bool includeWildcards)
{
InitializeIfMissing();
return includeWildcards == false
? _domains.Select(x => x.Value).Where(x => x.IsWildcard == false).OrderBy(x => x.SortOrder)
: _domains.Select(x => x.Value).OrderBy(x => x.SortOrder);
}
private void InitializeIfMissing()
{
if (_initialized)
{
return;
}
_initialized = true;
LoadDomains();
}
/// <inheritdoc />
public IEnumerable<Domain> GetAssigned(int documentId, bool includeWildcards = false)
{
InitializeIfMissing();
// probably this could be optimized with an index
// but then we'd need a custom DomainStore of some sort
IEnumerable<Domain> list = _domains.Values.Where(x => x.ContentId == documentId);
@@ -48,7 +61,10 @@ public class DomainCacheService : IDomainCacheService
/// <inheritdoc />
public bool HasAssigned(int documentId, bool includeWildcards = false)
=> documentId > 0 && GetAssigned(documentId, includeWildcards).Any();
{
InitializeIfMissing();
return documentId > 0 && GetAssigned(documentId, includeWildcards).Any();
}
public void Refresh(DomainCacheRefresher.JsonPayload[] payloads)
{
@@ -100,12 +116,19 @@ public class DomainCacheService : IDomainCacheService
private void LoadDomains()
{
IEnumerable<IDomain> domains = _domainService.GetAll(true);
foreach (Domain domain in domains
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId!.Value, x.LanguageIsoCode!, x.IsWildcard, x.SortOrder)))
using (ICoreScope scope = _coreScopeProvider.CreateCoreScope())
{
_domains.AddOrUpdate(domain.Id, domain, (key, oldValue) => domain);
scope.ReadLock(Constants.Locks.Domains);
IEnumerable<IDomain> domains = _domainService.GetAll(true);
foreach (Domain domain in domains
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId!.Value, x.LanguageIsoCode!, x.IsWildcard, x.SortOrder)))
{
_domains.AddOrUpdate(domain.Id, domain, (key, oldValue) => domain);
}
scope.Complete();
}
}
}

View File

@@ -18,4 +18,6 @@ public interface IDocumentCacheService
Task DeleteItemAsync(IContentBase content);
void Rebuild(IReadOnlyCollection<int> contentTypeKeys);
internal IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType);
}

View File

@@ -22,6 +22,12 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Tests</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Tests.Common</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Tests.UnitTests</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Tests.Integration</_Parameter1>
</AssemblyAttribute>