diff --git a/Directory.Packages.props b/Directory.Packages.props
index e60b2c718a..8bedbf588a 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -47,10 +47,10 @@
-
+
-
+
@@ -61,7 +61,7 @@
-
+
@@ -75,12 +75,12 @@
-
+
-
+
@@ -91,7 +91,6 @@
-
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
index 76ce80898f..f7fa2f6d92 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
@@ -12,8 +12,10 @@ namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("2.0")]
public class ByIdMediaApiController : MediaApiControllerBase
{
- public ByIdMediaApiController(IPublishedSnapshotAccessor publishedSnapshotAccessor, IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
- : base(publishedSnapshotAccessor, apiMediaWithCropsResponseBuilder)
+ public ByIdMediaApiController(
+ IPublishedMediaCache publishedMediaCache,
+ IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
+ : base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
{
}
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
index 8a3f4c7ceb..957c982c38 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
@@ -13,8 +13,8 @@ namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("2.0")]
public class ByIdsMediaApiController : MediaApiControllerBase
{
- public ByIdsMediaApiController(IPublishedSnapshotAccessor publishedSnapshotAccessor, IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
- : base(publishedSnapshotAccessor, apiMediaWithCropsResponseBuilder)
+ public ByIdsMediaApiController(IPublishedMediaCache publishedMediaCache, IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
+ : base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
{
}
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
index ed5dc90187..0afedddffb 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
@@ -16,10 +16,10 @@ public class ByPathMediaApiController : MediaApiControllerBase
private readonly IApiMediaQueryService _apiMediaQueryService;
public ByPathMediaApiController(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IPublishedMediaCache publishedMediaCache,
IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder,
IApiMediaQueryService apiMediaQueryService)
- : base(publishedSnapshotAccessor, apiMediaWithCropsResponseBuilder)
+ : base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
=> _apiMediaQueryService = apiMediaQueryService;
[HttpGet("item/{*path}")]
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
index 5a9bc4763e..7807290cc4 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
@@ -20,18 +20,15 @@ namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
public abstract class MediaApiControllerBase : DeliveryApiControllerBase
{
private readonly IApiMediaWithCropsResponseBuilder _apiMediaWithCropsResponseBuilder;
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
- private IPublishedMediaCache? _publishedMediaCache;
+ private IPublishedMediaCache _publishedMediaCache;
- protected MediaApiControllerBase(IPublishedSnapshotAccessor publishedSnapshotAccessor, IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
+ protected MediaApiControllerBase(IPublishedMediaCache publishedMediaCache, IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+ _publishedMediaCache = publishedMediaCache;
_apiMediaWithCropsResponseBuilder = apiMediaWithCropsResponseBuilder;
}
- protected IPublishedMediaCache PublishedMediaCache => _publishedMediaCache
- ??= _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Media
- ?? throw new InvalidOperationException("Could not obtain the published media cache");
+ protected IPublishedMediaCache PublishedMediaCache => _publishedMediaCache;
protected IApiMediaWithCropsResponse BuildApiMediaWithCrops(IPublishedContent media)
=> _apiMediaWithCropsResponseBuilder.Build(media);
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
index de872e5d86..c61aaf8764 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
@@ -21,10 +21,10 @@ public class QueryMediaApiController : MediaApiControllerBase
private readonly IApiMediaQueryService _apiMediaQueryService;
public QueryMediaApiController(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IPublishedMediaCache publishedMediaCache,
IApiMediaWithCropsResponseBuilder apiMediaWithCropsResponseBuilder,
IApiMediaQueryService apiMediaQueryService)
- : base(publishedSnapshotAccessor, apiMediaWithCropsResponseBuilder)
+ : base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
=> _apiMediaQueryService = apiMediaQueryService;
[HttpGet]
diff --git a/src/Umbraco.Cms.Api.Delivery/Querying/QueryOptionBase.cs b/src/Umbraco.Cms.Api.Delivery/Querying/QueryOptionBase.cs
index d4d63acf2b..1576d0037f 100644
--- a/src/Umbraco.Cms.Api.Delivery/Querying/QueryOptionBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Querying/QueryOptionBase.cs
@@ -7,14 +7,15 @@ namespace Umbraco.Cms.Api.Delivery.Querying;
public abstract class QueryOptionBase
{
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
+ private readonly IPublishedContentCache _publishedContentCache;
private readonly IRequestRoutingService _requestRoutingService;
+
public QueryOptionBase(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IPublishedContentCache publishedContentCache,
IRequestRoutingService requestRoutingService)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+ _publishedContentCache = publishedContentCache;
_requestRoutingService = requestRoutingService;
}
@@ -30,11 +31,9 @@ public abstract class QueryOptionBase
return id;
}
- IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
-
// Check if the passed value is a path of a content item
var contentRoute = _requestRoutingService.GetContentRoute(queryStringValue);
- IPublishedContent? contentItem = publishedSnapshot.Content?.GetByRoute(contentRoute);
+ IPublishedContent? contentItem = _publishedContentCache.GetByRoute(contentRoute);
return contentItem?.Key;
}
diff --git a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/AncestorsSelector.cs b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/AncestorsSelector.cs
index 5e8e7e2019..dfb91cabb2 100644
--- a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/AncestorsSelector.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/AncestorsSelector.cs
@@ -1,19 +1,35 @@
+using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Delivery.Indexing.Selectors;
using Umbraco.Cms.Core.DeliveryApi;
+using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Querying.Selectors;
public sealed class AncestorsSelector : QueryOptionBase, ISelectorHandler
{
+ private readonly IPublishedContentCache _publishedContentCache;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
private const string AncestorsSpecifier = "ancestors:";
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
- public AncestorsSelector(IPublishedSnapshotAccessor publishedSnapshotAccessor, IRequestRoutingService requestRoutingService)
- : base(publishedSnapshotAccessor, requestRoutingService) =>
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+ public AncestorsSelector(
+ IPublishedContentCache publishedContentCache,
+ IRequestRoutingService requestRoutingService,
+ IDocumentNavigationQueryService navigationQueryService)
+ : base(publishedContentCache, requestRoutingService)
+ {
+ _publishedContentCache = publishedContentCache;
+ _navigationQueryService = navigationQueryService;
+ }
+
+ [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
+ public AncestorsSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
+ : this(publishedContentCache, requestRoutingService, StaticServiceProvider.Instance.GetRequiredService())
+ {
+ }
///
public bool CanHandle(string query)
@@ -37,12 +53,10 @@ public sealed class AncestorsSelector : QueryOptionBase, ISelectorHandler
};
}
- IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
-
- IPublishedContent contentItem = publishedSnapshot.Content?.GetById((Guid)id)
+ IPublishedContent contentItem = _publishedContentCache.GetById((Guid)id)
?? throw new InvalidOperationException("Could not obtain the content cache");
- var ancestorKeys = contentItem.Ancestors().Select(a => a.Key.ToString("D")).ToArray();
+ var ancestorKeys = contentItem.Ancestors(_publishedContentCache, _navigationQueryService).Select(a => a.Key.ToString("D")).ToArray();
return new SelectorOption
{
diff --git a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/ChildrenSelector.cs b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/ChildrenSelector.cs
index 838b5da776..9392ce8e02 100644
--- a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/ChildrenSelector.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/ChildrenSelector.cs
@@ -9,8 +9,8 @@ public sealed class ChildrenSelector : QueryOptionBase, ISelectorHandler
{
private const string ChildrenSpecifier = "children:";
- public ChildrenSelector(IPublishedSnapshotAccessor publishedSnapshotAccessor, IRequestRoutingService requestRoutingService)
- : base(publishedSnapshotAccessor, requestRoutingService)
+ public ChildrenSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
+ : base(publishedContentCache, requestRoutingService)
{
}
diff --git a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/DescendantsSelector.cs b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/DescendantsSelector.cs
index e3c9bf33fd..2a7512746e 100644
--- a/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/DescendantsSelector.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Querying/Selectors/DescendantsSelector.cs
@@ -9,8 +9,8 @@ public sealed class DescendantsSelector : QueryOptionBase, ISelectorHandler
{
private const string DescendantsSpecifier = "descendants:";
- public DescendantsSelector(IPublishedSnapshotAccessor publishedSnapshotAccessor, IRequestRoutingService requestRoutingService)
- : base(publishedSnapshotAccessor, requestRoutingService)
+ public DescendantsSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
+ : base(publishedContentCache, requestRoutingService)
{
}
diff --git a/src/Umbraco.Cms.Api.Delivery/Services/ApiMediaQueryService.cs b/src/Umbraco.Cms.Api.Delivery/Services/ApiMediaQueryService.cs
index 8a078d7f0d..7979895ba3 100644
--- a/src/Umbraco.Cms.Api.Delivery/Services/ApiMediaQueryService.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Services/ApiMediaQueryService.cs
@@ -4,6 +4,7 @@ using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Extensions;
@@ -12,13 +13,15 @@ namespace Umbraco.Cms.Api.Delivery.Services;
///
internal sealed class ApiMediaQueryService : IApiMediaQueryService
{
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
+ private readonly IPublishedMediaCache _publishedMediaCache;
private readonly ILogger _logger;
+ private readonly IMediaNavigationQueryService _mediaNavigationQueryService;
- public ApiMediaQueryService(IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger)
+ public ApiMediaQueryService(IPublishedMediaCache publishedMediaCache, ILogger logger, IMediaNavigationQueryService mediaNavigationQueryService)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+ _publishedMediaCache = publishedMediaCache;
_logger = logger;
+ _mediaNavigationQueryService = mediaNavigationQueryService;
}
///
@@ -52,8 +55,7 @@ internal sealed class ApiMediaQueryService : IApiMediaQueryService
=> TryGetByPath(path, GetRequiredPublishedMediaCache());
private IPublishedMediaCache GetRequiredPublishedMediaCache()
- => _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Media
- ?? throw new InvalidOperationException("Could not obtain the published media cache");
+ => _publishedMediaCache;
private IPublishedContent? TryGetByPath(string path, IPublishedMediaCache mediaCache)
{
@@ -69,7 +71,7 @@ internal sealed class ApiMediaQueryService : IApiMediaQueryService
break;
}
- currentChildren = resolvedMedia.Children;
+ currentChildren = resolvedMedia.Children(null, _publishedMediaCache, _mediaNavigationQueryService);
}
return resolvedMedia;
@@ -102,7 +104,7 @@ internal sealed class ApiMediaQueryService : IApiMediaQueryService
? mediaCache.GetById(parentKey)
: TryGetByPath(childrenOf, mediaCache);
- return parent?.Children ?? Array.Empty();
+ return parent?.Children(null, _publishedMediaCache, _mediaNavigationQueryService) ?? Array.Empty();
}
private IEnumerable? ApplyFilters(IEnumerable source, IEnumerable filters)
diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RequestRedirectService.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestRedirectService.cs
index 4b9efc03a5..2f74d86364 100644
--- a/src/Umbraco.Cms.Api.Delivery/Services/RequestRedirectService.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestRedirectService.cs
@@ -21,7 +21,7 @@ internal sealed class RequestRedirectService : RoutingServiceBase, IRequestRedir
private readonly GlobalSettings _globalSettings;
public RequestRedirectService(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IDomainCache domainCache,
IHttpContextAccessor httpContextAccessor,
IRequestStartItemProviderAccessor requestStartItemProviderAccessor,
IRequestCultureService requestCultureService,
@@ -29,7 +29,7 @@ internal sealed class RequestRedirectService : RoutingServiceBase, IRequestRedir
IApiPublishedContentCache apiPublishedContentCache,
IApiContentRouteBuilder apiContentRouteBuilder,
IOptions globalSettings)
- : base(publishedSnapshotAccessor, httpContextAccessor, requestStartItemProviderAccessor)
+ : base(domainCache, httpContextAccessor, requestStartItemProviderAccessor)
{
_requestCultureService = requestCultureService;
_redirectUrlService = redirectUrlService;
diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RequestRoutingService.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestRoutingService.cs
index 6bf0dbc887..67cf9c9fc0 100644
--- a/src/Umbraco.Cms.Api.Delivery/Services/RequestRoutingService.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestRoutingService.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Umbraco.Cms.Core.DeliveryApi;
+using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
@@ -12,11 +13,11 @@ internal sealed class RequestRoutingService : RoutingServiceBase, IRequestRoutin
private readonly IRequestCultureService _requestCultureService;
public RequestRoutingService(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IDomainCache domainCache,
IHttpContextAccessor httpContextAccessor,
IRequestStartItemProviderAccessor requestStartItemProviderAccessor,
IRequestCultureService requestCultureService)
- : base(publishedSnapshotAccessor, httpContextAccessor, requestStartItemProviderAccessor) =>
+ : base(domainCache, httpContextAccessor, requestStartItemProviderAccessor) =>
_requestCultureService = requestCultureService;
///
diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs
index dd72d930bd..e79a2cbdd7 100644
--- a/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs
@@ -3,29 +3,34 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Services;
internal sealed class RequestStartItemProvider : RequestHeaderHandler, IRequestStartItemProvider
{
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IRequestPreviewService _requestPreviewService;
+ private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
+ private readonly IPublishedContentCache _publishedContentCache;
// this provider lifetime is Scope, so we can cache this as a field
private IPublishedContent? _requestedStartContent;
public RequestStartItemProvider(
IHttpContextAccessor httpContextAccessor,
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
- IRequestPreviewService requestPreviewService)
+ IRequestPreviewService requestPreviewService,
+ IDocumentNavigationQueryService documentNavigationQueryService,
+ IPublishedContentCache publishedContentCache)
: base(httpContextAccessor)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+
_variationContextAccessor = variationContextAccessor;
_requestPreviewService = requestPreviewService;
+ _documentNavigationQueryService = documentNavigationQueryService;
+ _publishedContentCache = publishedContentCache;
}
///
@@ -42,13 +47,11 @@ internal sealed class RequestStartItemProvider : RequestHeaderHandler, IRequestS
return null;
}
- if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) == false ||
- publishedSnapshot?.Content == null)
- {
- return null;
- }
-
- IEnumerable rootContent = publishedSnapshot.Content.GetAtRoot(_requestPreviewService.IsPreview());
+ _documentNavigationQueryService.TryGetRootKeys(out IEnumerable rootKeys);
+ IEnumerable rootContent = rootKeys
+ .Select(_publishedContentCache.GetById)
+ .WhereNotNull()
+ .Where(x => x.IsPublished() != _requestPreviewService.IsPreview());
_requestedStartContent = Guid.TryParse(headerValue, out Guid key)
? rootContent.FirstOrDefault(c => c.Key == key)
diff --git a/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs b/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs
index 32a8affd61..4a05521b22 100644
--- a/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Services/RoutingServiceBase.cs
@@ -9,16 +9,16 @@ namespace Umbraco.Cms.Api.Delivery.Services;
internal abstract class RoutingServiceBase
{
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
+ private readonly IDomainCache _domainCache;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IRequestStartItemProviderAccessor _requestStartItemProviderAccessor;
protected RoutingServiceBase(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IDomainCache domainCache,
IHttpContextAccessor httpContextAccessor,
IRequestStartItemProviderAccessor requestStartItemProviderAccessor)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
+ _domainCache = domainCache;
_httpContextAccessor = httpContextAccessor;
_requestStartItemProviderAccessor = requestStartItemProviderAccessor;
}
@@ -40,15 +40,9 @@ internal abstract class RoutingServiceBase
protected DomainAndUri? GetDomainAndUriForRoute(Uri contentUrl)
{
- IDomainCache? domainCache = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Domains;
- if (domainCache == null)
- {
- throw new InvalidOperationException("Could not obtain the domain cache in the current context");
- }
+ IEnumerable domains = _domainCache.GetAll(false);
- IEnumerable domains = domainCache.GetAll(false);
-
- return DomainUtilities.SelectDomain(domains, contentUrl, defaultCulture: domainCache.DefaultCulture);
+ return DomainUtilities.SelectDomain(domains, contentUrl, defaultCulture: _domainCache.DefaultCulture);
}
protected IPublishedContent? GetStartItem()
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/CollectPublishedCacheController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/CollectPublishedCacheController.cs
index 1337ece12a..4cbac68446 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/CollectPublishedCacheController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/CollectPublishedCacheController.cs
@@ -5,21 +5,15 @@ using Umbraco.Cms.Core.PublishedCache;
namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache;
+[Obsolete("This controller no longer serves a purpose")]
[ApiVersion("1.0")]
public class CollectPublishedCacheController : PublishedCacheControllerBase
{
- private readonly IPublishedSnapshotService _publishedSnapshotService;
-
- public CollectPublishedCacheController(IPublishedSnapshotService publishedSnapshotService)
- => _publishedSnapshotService = publishedSnapshotService;
-
[HttpPost("collect")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task Collect(CancellationToken cancellationToken)
{
- GC.Collect();
- await _publishedSnapshotService.CollectAsync();
return Ok();
}
}
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs
index b0e423e7e6..d48ad9fdbb 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs
@@ -8,17 +8,16 @@ namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache;
[ApiVersion("1.0")]
public class RebuildPublishedCacheController : PublishedCacheControllerBase
{
- private readonly IPublishedSnapshotService _publishedSnapshotService;
+ private readonly IDatabaseCacheRebuilder _databaseCacheRebuilder;
- public RebuildPublishedCacheController(IPublishedSnapshotService publishedSnapshotService)
- => _publishedSnapshotService = publishedSnapshotService;
+ public RebuildPublishedCacheController(IDatabaseCacheRebuilder databaseCacheRebuilder) => _databaseCacheRebuilder = databaseCacheRebuilder;
[HttpPost("rebuild")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task Rebuild(CancellationToken cancellationToken)
{
- _publishedSnapshotService.Rebuild();
+ _databaseCacheRebuilder.Rebuild();
return await Task.FromResult(Ok());
}
}
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/StatusPublishedCacheController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/StatusPublishedCacheController.cs
index e384742cb1..aad76e7dbf 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/StatusPublishedCacheController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/StatusPublishedCacheController.cs
@@ -6,16 +6,12 @@ using Umbraco.Cms.Core.PublishedCache;
namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache;
[ApiVersion("1.0")]
+[Obsolete("This no longer relevant since snapshots are no longer used")]
public class StatusPublishedCacheController : PublishedCacheControllerBase
{
- private readonly IPublishedSnapshotStatus _publishedSnapshotStatus;
-
- public StatusPublishedCacheController(IPublishedSnapshotStatus publishedSnapshotStatus)
- => _publishedSnapshotStatus = publishedSnapshotStatus;
-
[HttpGet("status")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
public async Task> Status(CancellationToken cancellationToken)
- => await Task.FromResult(Ok(_publishedSnapshotStatus.GetStatus()));
+ => await Task.FromResult(Ok("Obsoleted"));
}
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Template/Query/ExecuteTemplateQueryController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Template/Query/ExecuteTemplateQueryController.cs
index d74d299777..316dbdf51d 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Template/Query/ExecuteTemplateQueryController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Template/Query/ExecuteTemplateQueryController.cs
@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Linq.Expressions;
+using System.Runtime.Versioning;
using System.Text;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
@@ -8,7 +9,9 @@ using Umbraco.Cms.Api.Management.ViewModels.Template.Query;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Models.TemplateQuery;
+using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Controllers.Template.Query;
@@ -20,6 +23,8 @@ public class ExecuteTemplateQueryController : TemplateQueryControllerBase
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IPublishedValueFallback _publishedValueFallback;
private readonly IContentTypeService _contentTypeService;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
private static readonly string _indent = $"{Environment.NewLine} ";
@@ -27,12 +32,16 @@ public class ExecuteTemplateQueryController : TemplateQueryControllerBase
IPublishedContentQuery publishedContentQuery,
IVariationContextAccessor variationContextAccessor,
IPublishedValueFallback publishedValueFallback,
- IContentTypeService contentTypeService)
+ IContentTypeService contentTypeService,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService documentNavigationQueryService)
{
_publishedContentQuery = publishedContentQuery;
_variationContextAccessor = variationContextAccessor;
_publishedValueFallback = publishedValueFallback;
_contentTypeService = contentTypeService;
+ _contentCache = contentCache;
+ _documentNavigationQueryService = documentNavigationQueryService;
}
[HttpPost("execute")]
@@ -109,13 +118,13 @@ public class ExecuteTemplateQueryController : TemplateQueryControllerBase
queryExpression.Append($".ChildrenOfType(\"{model.DocumentTypeAlias}\")");
return rootContent == null
? Enumerable.Empty()
- : rootContent.ChildrenOfType(_variationContextAccessor, model.DocumentTypeAlias);
+ : rootContent.ChildrenOfType(_variationContextAccessor, _contentCache, _documentNavigationQueryService, model.DocumentTypeAlias);
}
queryExpression.Append(".Children()");
return rootContent == null
? Enumerable.Empty()
- : rootContent.Children(_variationContextAccessor);
+ : rootContent.Children(_variationContextAccessor, _contentCache, _documentNavigationQueryService);
}
private IEnumerable ApplyFiltering(IEnumerable? filters, IEnumerable contentQuery, StringBuilder queryExpression)
diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilder.BackOffice.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilder.BackOffice.cs
index f77afa7347..58024d471f 100644
--- a/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilder.BackOffice.cs
+++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilder.BackOffice.cs
@@ -34,7 +34,6 @@ public static partial class UmbracoBuilderExtensions
.AddMvcAndRazor(configureMvc)
.AddWebServer()
.AddRecurringBackgroundJobs()
- .AddNuCache()
.AddUmbracoHybridCache()
.AddDistributedCache()
.AddCoreNotifications()
diff --git a/src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs
index 459eed6e69..6d0e40e2b1 100644
--- a/src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs
+++ b/src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs
@@ -1,12 +1,13 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
@@ -16,10 +17,9 @@ public class DocumentUrlFactory : IDocumentUrlFactory
{
private readonly IDocumentUrlService _documentUrlService;
- public DocumentUrlFactory(
- IDocumentUrlService documentUrlService)
- {
+ public DocumentUrlFactory(IDocumentUrlService documentUrlService)
+ {
_documentUrlService = documentUrlService;
}
diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs
index 4ba8edf445..7f8484fca4 100644
--- a/src/Umbraco.Core/Cache/CacheKeys.cs
+++ b/src/Umbraco.Core/Cache/CacheKeys.cs
@@ -19,4 +19,7 @@ public static class CacheKeys
public const string ContentRecycleBinCacheKey = "recycleBin_content";
public const string MediaRecycleBinCacheKey = "recycleBin_media";
+
+ public const string PreviewPropertyCacheKeyPrefix = "Cache.Property.CacheValues[D:";
+ public const string PropertyCacheKeyPrefix = "Cache.Property.CacheValues[P:";
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs
index d2f3e0a6cd..8a3147f022 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs
@@ -17,56 +17,30 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase
{
private readonly IDomainService _domainService;
+ private readonly IDomainCacheService _domainCacheService;
private readonly IDocumentUrlService _documentUrlService;
private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
private readonly IDocumentNavigationManagementService _documentNavigationManagementService;
private readonly IContentService _contentService;
private readonly IIdKeyMap _idKeyMap;
- private readonly IPublishedSnapshotService _publishedSnapshotService;
-
- [Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 16")]
- public ContentCacheRefresher(
- AppCaches appCaches,
- IJsonSerializer serializer,
- IPublishedSnapshotService publishedSnapshotService,
- IIdKeyMap idKeyMap,
- IDomainService domainService,
- IEventAggregator eventAggregator,
- ICacheRefresherNotificationFactory factory)
- : this(
- appCaches,
- serializer,
- publishedSnapshotService,
- idKeyMap,
- domainService,
- eventAggregator,
- factory,
- StaticServiceProvider.Instance.GetRequiredService(),
- StaticServiceProvider.Instance.GetRequiredService(),
- StaticServiceProvider.Instance.GetRequiredService(),
- StaticServiceProvider.Instance.GetRequiredService()
- )
- {
-
- }
public ContentCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
- IPublishedSnapshotService publishedSnapshotService,
IIdKeyMap idKeyMap,
IDomainService domainService,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IDocumentUrlService documentUrlService,
+ IDomainCacheService domainCacheService,
IDocumentNavigationQueryService documentNavigationQueryService,
IDocumentNavigationManagementService documentNavigationManagementService,
IContentService contentService)
: base(appCaches, serializer, eventAggregator, factory)
{
- _publishedSnapshotService = publishedSnapshotService;
_idKeyMap = idKeyMap;
_domainService = domainService;
+ _domainCacheService = domainCacheService;
_documentUrlService = documentUrlService;
_documentNavigationQueryService = documentNavigationQueryService;
_documentNavigationManagementService = documentNavigationManagementService;
@@ -159,25 +133,11 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase new DomainCacheRefresher.JsonPayload(x.Id, DomainChangeTypes.Remove)).ToArray());
}
}
- // note: must do what's above FIRST else the repositories still have the old cached
- // content and when the PublishedCachesService is notified of changes it does not see
- // the new content...
-
- // TODO: what about this?
- // should rename it, and then, this is only for Deploy, and then, ???
- // if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
- // ...
- if (payloads.Any(x => x.Blueprint is false))
- {
- // Only notify if the payload contains actual (non-blueprint) contents
- NotifyPublishedSnapshotService(_publishedSnapshotService, AppCaches, payloads);
- }
-
base.Refresh(payloads);
}
@@ -326,24 +286,6 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase
- /// Refreshes the publish snapshot service and if there are published changes ensures that partial view caches are
- /// refreshed too
- ///
- ///
- ///
- ///
- internal static void NotifyPublishedSnapshotService(IPublishedSnapshotService service, AppCaches appCaches, JsonPayload[] payloads)
- {
- service.Notify(payloads, out _, out var publishedChanged);
-
- if (payloads.Any(x => x.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) || publishedChanged)
- {
- // when a public version changes
- appCaches.ClearPartialViewCache();
- }
- }
-
// TODO (V14): Change into a record
public class JsonPayload
{
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
index e1a82d6108..dba66ec1b0 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
@@ -3,7 +3,6 @@ using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Persistence.Repositories;
-using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Changes;
@@ -14,25 +13,22 @@ namespace Umbraco.Cms.Core.Cache;
public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase
{
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
- private readonly IIdKeyMap _idKeyMap;
private readonly IPublishedModelFactory _publishedModelFactory;
- private readonly IPublishedSnapshotService _publishedSnapshotService;
+ private readonly IIdKeyMap _idKeyMap;
public ContentTypeCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
- IPublishedSnapshotService publishedSnapshotService,
- IPublishedModelFactory publishedModelFactory,
IIdKeyMap idKeyMap,
IContentTypeCommonRepository contentTypeCommonRepository,
IEventAggregator eventAggregator,
- ICacheRefresherNotificationFactory factory)
+ ICacheRefresherNotificationFactory factory,
+ IPublishedModelFactory publishedModelFactory)
: base(appCaches, serializer, eventAggregator, factory)
{
- _publishedSnapshotService = publishedSnapshotService;
- _publishedModelFactory = publishedModelFactory;
_idKeyMap = idKeyMap;
_contentTypeCommonRepository = contentTypeCommonRepository;
+ _publishedModelFactory = publishedModelFactory;
}
#region Json
@@ -115,9 +111,8 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase
- _publishedSnapshotService.Notify(payloads));
+ // TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
+ _publishedModelFactory.WithSafeLiveFactoryReset(() => { });
// now we can trigger the event
base.Refresh(payloads);
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
index 394630fa64..f28dd89ea5 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
@@ -3,8 +3,6 @@ using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Persistence.Repositories;
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
-using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
@@ -15,21 +13,18 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase
- _publishedSnapshotService.Notify(payloads));
+ // TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
+ _publishedModelFactory.WithSafeLiveFactoryReset(() => { });
base.Refresh(payloads);
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
index fda11d6a91..4c765cda71 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
@@ -9,19 +9,16 @@ namespace Umbraco.Cms.Core.Cache;
public sealed class DomainCacheRefresher : PayloadCacheRefresherBase
{
- private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IDomainCacheService _domainCacheService;
public DomainCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
- IPublishedSnapshotService publishedSnapshotService,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IDomainCacheService domainCacheService)
: base(appCaches, serializer, eventAggregator, factory)
{
- _publishedSnapshotService = publishedSnapshotService;
_domainCacheService = domainCacheService;
}
@@ -63,10 +60,7 @@ public sealed class DomainCacheRefresher : PayloadCacheRefresherBase
{
+ private readonly IDomainCacheService _domainCacheService;
+
public LanguageCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
- IPublishedSnapshotService publishedSnapshotService,
IEventAggregator eventAggregator,
+ IDomainCacheService domainCache,
ICacheRefresherNotificationFactory factory)
- : base(appCaches, serializer, eventAggregator, factory) =>
- _publishedSnapshotService = publishedSnapshotService;
+ : base(appCaches, serializer, eventAggregator, factory)
+ {
+ _domainCacheService = domainCache;
+ }
///
/// Clears all domain caches
@@ -34,7 +38,7 @@ public sealed class LanguageCacheRefresher : PayloadCacheRefresherBase UniqueId;
@@ -141,8 +144,6 @@ public sealed class LanguageCacheRefresher : PayloadCacheRefresherBase
- /// Sets the published snapshot service.
- ///
- /// The builder.
- /// A function creating a published snapshot service.
- public static IUmbracoBuilder SetPublishedSnapshotService(
- this IUmbracoBuilder builder,
- Func factory)
- {
- builder.Services.AddUnique(factory);
- return builder;
- }
-
- ///
- /// Sets the published snapshot service.
- ///
- /// The type of the published snapshot service.
- /// The builder.
- public static IUmbracoBuilder SetPublishedSnapshotService(this IUmbracoBuilder builder)
- where T : class, IPublishedSnapshotService
- {
- builder.Services.AddUnique();
- return builder;
- }
-
- ///
- /// Sets the published snapshot service.
- ///
- /// The builder.
- /// A published snapshot service.
- public static IUmbracoBuilder SetPublishedSnapshotService(
- this IUmbracoBuilder builder,
- IPublishedSnapshotService service)
- {
- builder.Services.AddUnique(service);
- return builder;
- }
-}
diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs
index d33406a95a..45bb26cb0c 100644
--- a/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs
+++ b/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs
@@ -1,11 +1,9 @@
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
-using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
-using Umbraco.Cms.Core.Routing;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.DeliveryApi;
@@ -15,47 +13,25 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder
private readonly IApiContentPathProvider _apiContentPathProvider;
private readonly GlobalSettings _globalSettings;
private readonly IVariationContextAccessor _variationContextAccessor;
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IRequestPreviewService _requestPreviewService;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
private RequestHandlerSettings _requestSettings;
- [Obsolete($"Use the constructor that does not accept {nameof(IPublishedUrlProvider)}. Will be removed in V15.")]
- public ApiContentRouteBuilder(
- IPublishedUrlProvider publishedUrlProvider,
- IOptions globalSettings,
- IVariationContextAccessor variationContextAccessor,
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
- IRequestPreviewService requestPreviewService,
- IOptionsMonitor requestSettings)
- : this(StaticServiceProvider.Instance.GetRequiredService(), globalSettings, variationContextAccessor, publishedSnapshotAccessor, requestPreviewService, requestSettings)
- {
- }
-
- [Obsolete($"Use the constructor that does not accept {nameof(IPublishedUrlProvider)}. Will be removed in V15.")]
- public ApiContentRouteBuilder(
- IPublishedUrlProvider publishedUrlProvider,
- IApiContentPathProvider apiContentPathProvider,
- IOptions globalSettings,
- IVariationContextAccessor variationContextAccessor,
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
- IRequestPreviewService requestPreviewService,
- IOptionsMonitor requestSettings)
- : this(apiContentPathProvider, globalSettings, variationContextAccessor, publishedSnapshotAccessor, requestPreviewService, requestSettings)
- {
- }
-
public ApiContentRouteBuilder(
IApiContentPathProvider apiContentPathProvider,
IOptions globalSettings,
IVariationContextAccessor variationContextAccessor,
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
IRequestPreviewService requestPreviewService,
- IOptionsMonitor requestSettings)
+ IOptionsMonitor requestSettings,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService navigationQueryService)
{
_apiContentPathProvider = apiContentPathProvider;
_variationContextAccessor = variationContextAccessor;
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
_requestPreviewService = requestPreviewService;
+ _contentCache = contentCache;
+ _navigationQueryService = navigationQueryService;
_globalSettings = globalSettings.Value;
_requestSettings = requestSettings.CurrentValue;
requestSettings.OnChange(settings => _requestSettings = settings);
@@ -106,7 +82,7 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder
// we can perform fallback to the content route.
if (IsInvalidContentPath(contentPath))
{
- contentPath = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Content?.GetRouteById(content.Id, culture) ?? contentPath;
+ contentPath = _contentCache.GetRouteById(content.Id, culture) ?? contentPath;
}
// if the content path has still not been resolved as a valid path, the content is un-routable in this culture
@@ -129,16 +105,15 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder
{
if (isPreview is false)
{
- return content.Root();
+ return content.Root(_contentCache, _navigationQueryService);
}
+ _navigationQueryService.TryGetRootKeys(out IEnumerable rootKeys);
+ IEnumerable rootContent = rootKeys.Select(x => _contentCache.GetById(true, x)).WhereNotNull();
+
// in very edge case scenarios during preview, content.Root() does not map to the root.
// we'll code our way around it for the time being.
- return _publishedSnapshotAccessor
- .GetRequiredPublishedSnapshot()
- .Content?
- .GetAtRoot(true)
- .FirstOrDefault(root => root.IsAncestorOrSelf(content))
- ?? content.Root();
+ return rootContent.FirstOrDefault(root => root.IsAncestorOrSelf(content))
+ ?? content.Root(_contentCache, _navigationQueryService);
}
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
index 356150536d..829dbd7ae8 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
@@ -264,9 +264,6 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddSingleton();
- // register a basic/noop published snapshot service to be replaced
- Services.AddSingleton();
-
// Register ValueEditorCache used for validation
Services.AddSingleton();
diff --git a/src/Umbraco.Core/EmbeddedResources/Snippets/ListDescendantsFromCurrentPage.cshtml b/src/Umbraco.Core/EmbeddedResources/Snippets/ListDescendantsFromCurrentPage.cshtml
index 455236ac03..f174b38495 100644
--- a/src/Umbraco.Core/EmbeddedResources/Snippets/ListDescendantsFromCurrentPage.cshtml
+++ b/src/Umbraco.Core/EmbeddedResources/Snippets/ListDescendantsFromCurrentPage.cshtml
@@ -1,16 +1,21 @@
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models.PublishedContent
+@using Umbraco.Cms.Core.PublishedCache
@using Umbraco.Cms.Core.Routing
+@using Umbraco.Cms.Core.Services.Navigation
@using Umbraco.Extensions
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@inject IPublishedValueFallback PublishedValueFallback
@inject IPublishedUrlProvider PublishedUrlProvider
+@inject IVariationContextAccessor VariationContextAccessor
+@inject IPublishedContentCache PublishedContentCache
+@inject IDocumentNavigationQueryService DocumentNavigationQueryService
@*
This snippet creates links for every single page (no matter how deep) below
the page currently being viewed by the website visitor, displayed as nested unordered HTML lists.
*@
-@{ var selection = Model?.Content.Children.Where(x => x.IsVisible(PublishedValueFallback)).ToArray(); }
+@{ var selection = Model?.Content.Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService).Where(x => x.IsVisible(PublishedValueFallback)).ToArray(); }
@* Ensure that the Current Page has children *@
@if (selection?.Length > 0)
@@ -28,7 +33,11 @@
@* if this child page has any children, where the property umbracoNaviHide is not True *@
@{
- var children = item.Children.Where(x => x.IsVisible(PublishedValueFallback)).ToArray();
+ var children = item
+ .Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService)
+ .Where(x => x.IsVisible(PublishedValueFallback))
+ .ToArray();
+
if (children.Length > 0)
{
@* Call a local method to display the children *@
@@ -58,7 +67,11 @@
@* if the page has any children, where the property umbracoNaviHide is not True *@
@{
- var children = item.Children.Where(x => x.IsVisible(PublishedValueFallback)).ToArray();
+ var children = item
+ .Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService)
+ .Where(x => x.IsVisible(PublishedValueFallback))
+ .ToArray();
+
if (children.Length > 0)
{
@* Recurse and call the ChildPages method to display the children *@
diff --git a/src/Umbraco.Core/EmbeddedResources/Snippets/SiteMap.cshtml b/src/Umbraco.Core/EmbeddedResources/Snippets/SiteMap.cshtml
index 3a257cc161..20b31b6dcb 100644
--- a/src/Umbraco.Core/EmbeddedResources/Snippets/SiteMap.cshtml
+++ b/src/Umbraco.Core/EmbeddedResources/Snippets/SiteMap.cshtml
@@ -1,10 +1,15 @@
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models.PublishedContent
+@using Umbraco.Cms.Core.PublishedCache
@using Umbraco.Cms.Core.Routing
+@using Umbraco.Cms.Core.Services.Navigation
@using Umbraco.Extensions
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@inject IPublishedValueFallback PublishedValueFallback
@inject IPublishedUrlProvider PublishedUrlProvider
+@inject IVariationContextAccessor VariationContextAccessor
+@inject IPublishedContentCache PublishedContentCache
+@inject IDocumentNavigationQueryService DocumentNavigationQueryService
@*
This snippet makes a list of links of all visible pages of the site, as nested unordered HTML lists.
@@ -27,7 +32,10 @@
const int maxLevelForSitemap = 4;
@* Select visible children *@
- var selection = node?.Children.Where(x => x.IsVisible(PublishedValueFallback) && x.Level <= maxLevelForSitemap).ToArray();
+ var selection = node?
+ .Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService)
+ .Where(x => x.IsVisible(PublishedValueFallback) && x.Level <= maxLevelForSitemap)
+ .ToArray();
@* If any items are returned, render a list *@
if (selection?.Length > 0)
diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs
index ff4fd499f9..5139e23af9 100644
--- a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs
+++ b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs
@@ -9,6 +9,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Services.Navigation;
namespace Umbraco.Extensions;
@@ -119,16 +120,36 @@ public static class PublishedContentExtensions
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The parent of content, of the given content type, else null.
- public static T? Parent(this IPublishedContent content)
+ public static T? Parent(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent
{
- if (content == null)
+ ArgumentNullException.ThrowIfNull(content);
+
+ return content.GetParent(publishedCache, navigationQueryService) as T;
+ }
+
+ private static IPublishedContent? GetParent(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
+ {
+ IPublishedContent? parent;
+ if (navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey))
{
- throw new ArgumentNullException(nameof(content));
+ parent = parentKey.HasValue ? publishedCache.GetById(parentKey.Value) : null;
+ }
+ else
+ {
+ throw new KeyNotFoundException($"Content with key '{content.Key}' was not found in the in-memory navigation structure.");
}
- return content.Parent as T;
+ return parent;
}
#endregion
@@ -497,41 +518,63 @@ public static class PublishedContentExtensions
/// Gets the ancestors of the content.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The ancestors of the content, in down-top order.
/// Does not consider the content itself.
- public static IEnumerable Ancestors(this IPublishedContent content) =>
- content.AncestorsOrSelf(false, null);
+ public static IEnumerable Ancestors(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, false, null);
///
/// Gets the ancestors of the content, at a level lesser or equal to a specified level.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
/// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order.
/// Does not consider the content itself. Only content that are "high enough" in the tree are returned.
- public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel) =>
- content.AncestorsOrSelf(false, n => n.Level <= maxLevel);
+ public static IEnumerable Ancestors(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, false, n => n.Level <= maxLevel);
///
/// Gets the ancestors of the content, of a specified content type.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content type.
/// The ancestors of the content, of the specified content type, in down-top order.
/// Does not consider the content itself. Returns all ancestors, of the specified content type.
- public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias) =>
- content.AncestorsOrSelf(false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ public static IEnumerable Ancestors(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
///
/// Gets the ancestors of the content, of a specified content type.
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The ancestors of the content, of the specified content type, in down-top order.
/// Does not consider the content itself. Returns all ancestors, of the specified content type.
- public static IEnumerable Ancestors(this IPublishedContent content)
+ public static IEnumerable Ancestors(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent =>
- content.Ancestors().OfType();
+ content.Ancestors(publishedCache, navigationQueryService).OfType();
///
/// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content
@@ -539,6 +582,8 @@ public static class PublishedContentExtensions
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
///
/// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified
@@ -548,22 +593,33 @@ public static class PublishedContentExtensions
/// Does not consider the content itself. Only content that are "high enough" in the trees, and of the
/// specified content type, are returned.
///
- public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
+ public static IEnumerable Ancestors(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel)
where T : class, IPublishedContent =>
- content.Ancestors(maxLevel).OfType();
+ content.Ancestors(publishedCache, navigationQueryService, maxLevel).OfType();
///
/// Gets the content and its ancestors.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content and its ancestors, in down-top order.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content) =>
- content.AncestorsOrSelf(true, null);
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, true, null);
///
/// Gets the content and its ancestors, at a level lesser or equal to a specified level.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
///
/// The content and its ancestors, at a level lesser or equal to the specified level,
@@ -573,30 +629,44 @@ public static class PublishedContentExtensions
/// Only content that are "high enough" in the tree are returned. So it may or may not begin
/// with the content itself, depending on its level.
///
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel) =>
- content.AncestorsOrSelf(true, n => n.Level <= maxLevel);
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, true, n => n.Level <= maxLevel);
///
/// Gets the content and its ancestors, of a specified content type.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content type.
/// The content and its ancestors, of the specified content type, in down-top order.
/// May or may not begin with the content itself, depending on its content type.
- public static IEnumerable
- AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias) =>
- content.AncestorsOrSelf(true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
///
/// Gets the content and its ancestors, of a specified content type.
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content and its ancestors, of the specified content type, in down-top order.
/// May or may not begin with the content itself, depending on its content type.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent =>
- content.AncestorsOrSelf().OfType();
+ content.AncestorsOrSelf(publishedCache, navigationQueryService).OfType();
///
/// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content
@@ -604,69 +674,104 @@ public static class PublishedContentExtensions
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
///
/// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified
/// content type, in down-top order.
///
/// May or may not begin with the content itself, depending on its level and content type.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel)
where T : class, IPublishedContent =>
- content.AncestorsOrSelf(maxLevel).OfType();
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, maxLevel).OfType();
///
/// Gets the ancestor of the content, ie its parent.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The ancestor of the content.
/// This method is here for consistency purposes but does not make much sense.
- public static IPublishedContent? Ancestor(this IPublishedContent content) => content.Parent;
+ public static IPublishedContent? Ancestor(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
+ => content.GetParent(publishedCache, navigationQueryService);
///
/// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
/// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level.
/// Does not consider the content itself. May return null.
- public static IPublishedContent? Ancestor(this IPublishedContent content, int maxLevel) =>
- content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel);
+ public static IPublishedContent? Ancestor(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel) =>
+ content.EnumerateAncestors(publishedCache, navigationQueryService, false).FirstOrDefault(x => x.Level <= maxLevel);
///
/// Gets the nearest ancestor of the content, of a specified content type.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content type alias.
/// The nearest (in down-top order) ancestor of the content, of the specified content type.
/// Does not consider the content itself. May return null.
- public static IPublishedContent? Ancestor(this IPublishedContent content, string contentTypeAlias) => content
- .EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ public static IPublishedContent? Ancestor(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias) =>
+ content.EnumerateAncestors(publishedCache, navigationQueryService, false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
///
/// Gets the nearest ancestor of the content, of a specified content type.
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The nearest (in down-top order) ancestor of the content, of the specified content type.
/// Does not consider the content itself. May return null.
- public static T? Ancestor(this IPublishedContent content)
+ public static T? Ancestor(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent =>
- content.Ancestors().FirstOrDefault();
+ content.Ancestors(publishedCache, navigationQueryService).FirstOrDefault();
///
/// Gets the nearest ancestor of the content, at the specified level and of the specified content type.
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
/// The ancestor of the content, at the specified level and of the specified content type.
///
/// Does not consider the content itself. If the ancestor at the specified level is
/// not of the specified type, returns null.
///
- public static T? Ancestor(this IPublishedContent content, int maxLevel)
+ public static T? Ancestor(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel)
where T : class, IPublishedContent =>
- content.Ancestors(maxLevel).FirstOrDefault();
+ content.Ancestors(publishedCache, navigationQueryService, maxLevel).FirstOrDefault();
///
/// Gets the content or its nearest ancestor.
@@ -680,32 +785,49 @@ public static class PublishedContentExtensions
/// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
/// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level.
/// May or may not return the content itself depending on its level. May return null.
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel) =>
- content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel) ?? content;
+ public static IPublishedContent AncestorOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel) =>
+ content.EnumerateAncestors(publishedCache, navigationQueryService, true).FirstOrDefault(x => x.Level <= maxLevel) ?? content;
///
/// Gets the content or its nearest ancestor, of a specified content type.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content type.
/// The content or its nearest (in down-top order) ancestor, of the specified content type.
/// May or may not return the content itself depending on its content type. May return null.
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias) => content
- .EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)) ?? content;
+ public static IPublishedContent AncestorOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias) => content
+ .EnumerateAncestors(publishedCache, navigationQueryService, true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)) ?? content;
///
/// Gets the content or its nearest ancestor, of a specified content type.
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The content or its nearest (in down-top order) ancestor, of the specified content type.
/// May or may not return the content itself depending on its content type. May return null.
- public static T? AncestorOrSelf(this IPublishedContent content)
+ public static T? AncestorOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent =>
- content.AncestorsOrSelf().FirstOrDefault();
+ content.AncestorsOrSelf(publishedCache, navigationQueryService).FirstOrDefault();
///
/// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified
@@ -713,15 +835,26 @@ public static class PublishedContentExtensions
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The level.
///
- public static T? AncestorOrSelf(this IPublishedContent content, int maxLevel)
+ public static T? AncestorOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int maxLevel)
where T : class, IPublishedContent =>
- content.AncestorsOrSelf(maxLevel).FirstOrDefault();
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, maxLevel).FirstOrDefault();
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func? func)
+ public static IEnumerable AncestorsOrSelf(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ bool orSelf,
+ Func? func)
{
- IEnumerable ancestorsOrSelf = content.EnumerateAncestors(orSelf);
+ IEnumerable ancestorsOrSelf = content.EnumerateAncestors(publishedCache, navigationQueryService, orSelf);
return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func);
}
@@ -729,9 +862,15 @@ public static class PublishedContentExtensions
/// Enumerates ancestors of the content, bottom-up.
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// Indicates whether the content should be included.
/// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc).
- internal static IEnumerable EnumerateAncestors(this IPublishedContent? content, bool orSelf)
+ internal static IEnumerable EnumerateAncestors(
+ this IPublishedContent? content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ bool orSelf)
{
if (content == null)
{
@@ -743,7 +882,7 @@ public static class PublishedContentExtensions
yield return content;
}
- while ((content = content.Parent) != null)
+ while ((content = content.GetParent(publishedCache, navigationQueryService)) != null)
{
yield return content;
}
@@ -757,18 +896,26 @@ public static class PublishedContentExtensions
/// Gets the breadcrumbs (ancestors and self, top to bottom) for the specified .
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// Indicates whether the specified content should be included.
///
/// The breadcrumbs (ancestors and self, top to bottom) for the specified .
///
- public static IEnumerable Breadcrumbs(this IPublishedContent content, bool andSelf = true) =>
- content.AncestorsOrSelf(andSelf, null).Reverse();
+ public static IEnumerable Breadcrumbs(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ bool andSelf = true) =>
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, andSelf, null).Reverse();
///
/// Gets the breadcrumbs (ancestors and self, top to bottom) for the specified at a level
/// higher or equal to .
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// The minimum level.
/// Indicates whether the specified content should be included.
///
@@ -777,9 +924,11 @@ public static class PublishedContentExtensions
///
public static IEnumerable Breadcrumbs(
this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
int minLevel,
bool andSelf = true) =>
- content.AncestorsOrSelf(andSelf, n => n.Level >= minLevel).Reverse();
+ content.AncestorsOrSelf(publishedCache, navigationQueryService, andSelf, n => n.Level >= minLevel).Reverse();
///
/// Gets the breadcrumbs (ancestors and self, top to bottom) for the specified at a level
@@ -787,12 +936,18 @@ public static class PublishedContentExtensions
///
/// The root content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
/// Indicates whether the specified content should be included.
///
/// The breadcrumbs (ancestors and self, top to bottom) for the specified at a level higher
/// or equal to the specified root content type .
///
- public static IEnumerable Breadcrumbs(this IPublishedContent content, bool andSelf = true)
+ public static IEnumerable Breadcrumbs(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ bool andSelf = true)
where T : class, IPublishedContent
{
static IEnumerable TakeUntil(IEnumerable source, Func predicate)
@@ -807,7 +962,7 @@ public static class PublishedContentExtensions
}
}
- return TakeUntil(content.AncestorsOrSelf(andSelf, null), n => n is T).Reverse();
+ return TakeUntil(content.AncestorsOrSelf(publishedCache, navigationQueryService, andSelf, null), n => n is T).Reverse();
}
#endregion
@@ -819,18 +974,25 @@ public static class PublishedContentExtensions
///
///
/// Variation context accessor.
+ ///
///
///
/// The specific culture to filter for. If null is used the current culture is used. (Default is
/// null)
///
+ ///
///
///
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
///
public static IEnumerable DescendantsOrSelfOfType(
- this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string docTypeAlias, string? culture = null) => parentNodes.SelectMany(x =>
- x.DescendantsOrSelfOfType(variationContextAccessor, docTypeAlias, culture));
+ this IEnumerable parentNodes,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string docTypeAlias,
+ string? culture = null) => parentNodes.SelectMany(x =>
+ x.DescendantsOrSelfOfType(variationContextAccessor, publishedCache, navigationQueryService, docTypeAlias, culture));
///
/// Returns all DescendantsOrSelf of all content referenced
@@ -845,9 +1007,14 @@ public static class PublishedContentExtensions
///
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
///
- public static IEnumerable DescendantsOrSelf(this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static IEnumerable DescendantsOrSelf(
+ this IEnumerable parentNodes,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, culture));
+ parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, culture));
// as per XPath 1.0 specs �2.2,
// - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus
@@ -867,85 +1034,199 @@ public static class PublishedContentExtensions
// - every node occurs before all of its children and descendants.
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
// - children and descendants occur before following siblings.
- public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, false, null, culture);
+ public static IEnumerable Descendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, false, null, culture);
- public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, false, p => p.Level >= level, culture);
+ public static IEnumerable Descendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, false, p => p.Level >= level, culture);
- public static IEnumerable DescendantsOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ public static IEnumerable DescendantsOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias, string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
- public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static IEnumerable Descendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Descendants(variationContextAccessor, culture).OfType();
+ content.Descendants(variationContextAccessor, publishedCache, navigationQueryService, culture).OfType();
- public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
+ public static IEnumerable Descendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Descendants(variationContextAccessor, level, culture).OfType();
+ content.Descendants(variationContextAccessor, publishedCache, navigationQueryService, level, culture).OfType();
- public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, true, null, culture);
+ public static IEnumerable DescendantsOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, true, null, culture);
- public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, true, p => p.Level >= level, culture);
+ public static IEnumerable DescendantsOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, true, p => p.Level >= level, culture);
- public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) =>
- content.DescendantsOrSelf(variationContextAccessor, true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ public static IEnumerable DescendantsOrSelfOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias,
+ string? culture = null) =>
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
- public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static IEnumerable DescendantsOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.DescendantsOrSelf(variationContextAccessor, culture).OfType();
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, culture).OfType();
- public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
+ public static IEnumerable DescendantsOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.DescendantsOrSelf(variationContextAccessor, level, culture).OfType();
+ content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, level, culture).OfType();
- public static IPublishedContent? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) =>
- content.Children(variationContextAccessor, culture)?.FirstOrDefault();
+ public static IPublishedContent? Descendant(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null) =>
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault();
- public static IPublishedContent? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) => content
- .EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.Level == level);
+ public static IPublishedContent? Descendant(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null) => content
+ .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, false, culture).FirstOrDefault(x => x.Level == level);
- public static IPublishedContent? DescendantOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) => content
- .EnumerateDescendants(variationContextAccessor, false, culture)
+ public static IPublishedContent? DescendantOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias,
+ string? culture = null) => content
+ .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, false, culture)
.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
- public static T? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static T? Descendant(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x is T) as T;
+ content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, false, culture).FirstOrDefault(x => x is T) as T;
- public static T? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
+ public static T? Descendant(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Descendant(variationContextAccessor, level, culture) as T;
+ content.Descendant(variationContextAccessor, publishedCache, navigationQueryService, level, culture) as T;
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) => content;
- public static IPublishedContent? DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) => content
- .EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.Level == level);
+ public static IPublishedContent? DescendantOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null) => content
+ .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, true, culture).FirstOrDefault(x => x.Level == level);
- public static IPublishedContent? DescendantOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) => content
- .EnumerateDescendants(variationContextAccessor, true, culture)
+ public static IPublishedContent? DescendantOrSelfOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias,
+ string? culture = null) => content
+ .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, true, culture)
.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
- public static T? DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static T? DescendantOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x is T) as T;
+ content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, true, culture).FirstOrDefault(x => x is T) as T;
- public static T? DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
+ public static T? DescendantOrSelf(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ int level,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.DescendantOrSelf(variationContextAccessor, level, culture) as T;
+ content.DescendantOrSelf(variationContextAccessor, publishedCache, navigationQueryService, level, culture) as T;
internal static IEnumerable DescendantsOrSelf(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
bool orSelf,
Func? func,
string? culture = null) =>
- content.EnumerateDescendants(variationContextAccessor, orSelf, culture)
+ content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, orSelf, culture)
.Where(x => func == null || func(x));
- internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, bool orSelf, string? culture = null)
+ internal static IEnumerable EnumerateDescendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ bool orSelf,
+ string? culture = null)
{
if (content == null)
{
@@ -957,25 +1238,30 @@ public static class PublishedContentExtensions
yield return content;
}
- IEnumerable? children = content.Children(variationContextAccessor, culture);
+ IEnumerable? children = content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture);
if (children is not null)
{
foreach (IPublishedContent desc in children.SelectMany(x =>
- x.EnumerateDescendants(variationContextAccessor, culture)))
+ x.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, culture)))
{
yield return desc;
}
}
}
- internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ internal static IEnumerable EnumerateDescendants(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
{
yield return content;
- IEnumerable? children = content.Children(variationContextAccessor, culture);
+ IEnumerable? children = content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture);
if (children is not null)
{
foreach (IPublishedContent desc in children.SelectMany(x =>
- x.EnumerateDescendants(variationContextAccessor, culture)))
+ x.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, culture)))
{
yield return desc;
}
@@ -991,10 +1277,12 @@ public static class PublishedContentExtensions
///
/// The content item.
///
+ ///
///
/// The specific culture to get the URL children for. Default is null which will use the current culture in
///
///
+ ///
///
/// Gets children that are available for the specified culture.
/// Children are sorted by their sortOrder.
@@ -1012,18 +1300,32 @@ public static class PublishedContentExtensions
/// However, if an empty string is specified only invariant children are returned.
///
///
- public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, string? culture = null)
+ public static IEnumerable Children(
+ this IPublishedContent content,
+ IVariationContextAccessor? variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
{
// handle context culture for variant
- if (culture == null)
+ if (culture is null)
{
culture = variationContextAccessor?.VariationContext?.Culture ?? string.Empty;
}
- IEnumerable? children = content.ChildrenForAllCultures;
- return (culture == "*"
- ? children : children?.Where(x => x.IsInvariantOrHasCulture(culture)))
- ?? Enumerable.Empty();
+ if (navigationQueryService.TryGetChildrenKeys(content.Key, out IEnumerable childrenKeys) is false)
+ {
+ return [];
+ }
+
+ IEnumerable children = childrenKeys.Select(publishedCache.GetById).WhereNotNull();
+
+ if (culture == "*")
+ {
+ return children;
+ }
+
+ return children.Where(x => x.IsInvariantOrHasCulture(culture)) ?? [];
}
///
@@ -1031,11 +1333,13 @@ public static class PublishedContentExtensions
///
/// The content.
/// The accessor for VariationContext
+ ///
/// The predicate.
///
/// The specific culture to filter for. If null is used the current culture is used. (Default is
/// null)
///
+ ///
/// The children of the content, filtered by the predicate.
///
/// Children are sorted by their sortOrder.
@@ -1043,23 +1347,34 @@ public static class PublishedContentExtensions
public static IEnumerable Children(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
Func predicate,
string? culture = null) =>
- content.Children(variationContextAccessor, culture).Where(predicate);
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture).Where(predicate);
///
/// Gets the children of the content, of any of the specified types.
///
/// The content.
+ ///
/// The accessor for the VariationContext
///
/// The specific culture to filter for. If null is used the current culture is used. (Default is
/// null)
///
/// The content type alias.
+ ///
/// The children of the content, of any of the specified types.
- public static IEnumerable ChildrenOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? contentTypeAlias, string? culture = null) =>
- content.Children(variationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ public static IEnumerable ChildrenOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? contentTypeAlias,
+ string? culture = null) =>
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias),
+ culture);
///
/// Gets the children of the content, of a given content type.
@@ -1075,31 +1390,71 @@ public static class PublishedContentExtensions
///
/// Children are sorted by their sortOrder.
///
- public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static IEnumerable Children(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Children(variationContextAccessor, culture).OfType();
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture).OfType();
- public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) =>
- content.Children(variationContextAccessor, culture)?.FirstOrDefault();
+ public static IPublishedContent? FirstChild(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null) =>
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault();
///
/// Gets the first child of the content, of a given content type.
///
- public static IPublishedContent? FirstChildOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) =>
- content.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture)?.FirstOrDefault();
+ public static IPublishedContent? FirstChildOfType(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string contentTypeAlias,
+ string? culture = null) =>
+ content.ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture)?.FirstOrDefault();
- public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string? culture = null) => content.Children(variationContextAccessor, predicate, culture)?.FirstOrDefault();
+ public static IPublishedContent? FirstChild(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ Func predicate,
+ string? culture = null)
+ => content.Children(variationContextAccessor, publishedCache, navigationQueryService, predicate, culture)?.FirstOrDefault();
- public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Guid uniqueId, string? culture = null) => content
- .Children(variationContextAccessor, x => x.Key == uniqueId, culture)?.FirstOrDefault();
+ public static IPublishedContent? FirstChild(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ Guid uniqueId,
+ string? culture = null) => content
+ .Children(variationContextAccessor, publishedCache, navigationQueryService, x => x.Key == uniqueId, culture)?.FirstOrDefault();
- public static T? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static T? FirstChild(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Children(variationContextAccessor, culture)?.FirstOrDefault();
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault();
- public static T? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string? culture = null)
+ public static T? FirstChild(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ Func predicate,
+ string? culture = null)
where T : class, IPublishedContent =>
- content.Children(variationContextAccessor, culture)?.FirstOrDefault(predicate);
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault(predicate);
#endregion
@@ -1109,22 +1464,24 @@ public static class PublishedContentExtensions
/// Gets the siblings of the content.
///
/// The content.
- /// Published snapshot instance
+ /// The navigation service
/// Variation context accessor.
///
/// The specific culture to filter for. If null is used the current culture is used. (Default is
/// null)
///
+ /// The content cache instance.
/// The siblings of the content.
///
/// Note that in V7 this method also return the content node self.
///
public static IEnumerable Siblings(
this IPublishedContent content,
- IPublishedSnapshot? publishedSnapshot,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
- SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture)
+ SiblingsAndSelf(content, publishedCache, navigationQueryService, variationContextAccessor, culture)
?.Where(x => x.Id != content.Id) ?? Enumerable.Empty();
///
@@ -1144,11 +1501,12 @@ public static class PublishedContentExtensions
///
public static IEnumerable SiblingsOfType(
this IPublishedContent content,
- IPublishedSnapshot? publishedSnapshot,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
string contentTypeAlias,
string? culture = null) =>
- SiblingsAndSelfOfType(content, publishedSnapshot, variationContextAccessor, contentTypeAlias, culture)
+ SiblingsAndSelfOfType(content, variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture)
?.Where(x => x.Id != content.Id) ?? Enumerable.Empty();
///
@@ -1166,16 +1524,22 @@ public static class PublishedContentExtensions
///
/// Note that in V7 this method also return the content node self.
///
- public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null)
+ public static IEnumerable Siblings(
+ this IPublishedContent content,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
+ string? culture = null)
where T : class, IPublishedContent =>
- SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture)
+ SiblingsAndSelf(content, variationContextAccessor, publishedCache, navigationQueryService, culture)
?.Where(x => x.Id != content.Id) ?? Enumerable.Empty();
///
/// Gets the siblings of the content including the node itself to indicate the position.
///
/// The content.
- /// Published snapshot instance
+ /// Cache instance.
+ /// The navigation service.
/// Variation context accessor.
///
/// The specific culture to filter for. If null is used the current culture is used. (Default is
@@ -1184,13 +1548,30 @@ public static class PublishedContentExtensions
/// The siblings of the content including the node itself.
public static IEnumerable? SiblingsAndSelf(
this IPublishedContent content,
- IPublishedSnapshot? publishedSnapshot,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
IVariationContextAccessor variationContextAccessor,
- string? culture = null) =>
- content.Parent != null
- ? content.Parent.Children(variationContextAccessor, culture)
- : publishedSnapshot?.Content?.GetAtRoot(culture)
+ string? culture = null)
+ {
+ var success = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey);
+
+ if (success is false || parentKey is null)
+ {
+ if (navigationQueryService.TryGetRootKeys(out IEnumerable childrenKeys) is false)
+ {
+ return null;
+ }
+
+ return childrenKeys
+ .Select(publishedCache.GetById)
+ .WhereNotNull()
.WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
+ }
+
+ return navigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable siblingKeys) is false
+ ? null
+ : siblingKeys.Select(publishedCache.GetById).WhereNotNull();
+ }
///
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
@@ -1206,15 +1587,33 @@ public static class PublishedContentExtensions
/// The siblings of the content including the node itself, of the given content type.
public static IEnumerable SiblingsAndSelfOfType(
this IPublishedContent content,
- IPublishedSnapshot? publishedSnapshot,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
string contentTypeAlias,
- string? culture = null) =>
- (content.Parent != null
- ? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture)
- : publishedSnapshot?.Content?.GetAtRoot(culture).OfTypes(contentTypeAlias)
- .WhereIsInvariantOrHasCulture(variationContextAccessor, culture))
- ?? Enumerable.Empty();
+ string? culture = null)
+ {
+
+ var parentSuccess = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey);
+
+ IPublishedContent? parent = parentKey is null ? null : publishedCache.GetById(parentKey.Value);
+
+ if (parentSuccess is false || parent is null)
+ {
+ if (navigationQueryService.TryGetRootKeys(out IEnumerable childrenKeys) is false)
+ {
+ return Enumerable.Empty();
+ }
+
+ return childrenKeys
+ .Select(publishedCache.GetById)
+ .WhereNotNull()
+ .OfTypes(contentTypeAlias)
+ .WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
+ }
+
+ return parent.ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture);
+ }
///
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
@@ -1230,15 +1629,32 @@ public static class PublishedContentExtensions
/// The siblings of the content including the node itself, of the given content type.
public static IEnumerable SiblingsAndSelf(
this IPublishedContent content,
- IPublishedSnapshot? publishedSnapshot,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
string? culture = null)
- where T : class, IPublishedContent =>
- (content.Parent != null
- ? content.Parent.Children(variationContextAccessor, culture)
- : publishedSnapshot?.Content?.GetAtRoot(culture).OfType()
- .WhereIsInvariantOrHasCulture(variationContextAccessor, culture))
- ?? Enumerable.Empty();
+ where T : class, IPublishedContent
+ {
+ var parentSuccess = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey);
+ IPublishedContent? parent = parentKey is null ? null : publishedCache.GetById(parentKey.Value);
+
+ if (parentSuccess is false || parent is null)
+ {
+ var rootSuccess = navigationQueryService.TryGetRootKeys(out IEnumerable rootKeys);
+ if (rootSuccess is false)
+ {
+ return [];
+ }
+
+ return rootKeys
+ .Select(publishedCache.GetById)
+ .WhereNotNull()
+ .WhereIsInvariantOrHasCulture(variationContextAccessor, culture)
+ .OfType();
+ }
+
+ return parent.Children(variationContextAccessor, publishedCache, navigationQueryService, culture);
+ }
#endregion
@@ -1248,6 +1664,8 @@ public static class PublishedContentExtensions
/// Gets the root content (ancestor or self at level 1) for the specified .
///
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
///
/// The root content (ancestor or self at level 1) for the specified .
///
@@ -1256,7 +1674,10 @@ public static class PublishedContentExtensions
/// with maxLevel
/// set to 1.
///
- public static IPublishedContent Root(this IPublishedContent content) => content.AncestorOrSelf(1);
+ public static IPublishedContent Root(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService) => content.AncestorOrSelf(publishedCache, navigationQueryService, 1);
///
/// Gets the root content (ancestor or self at level 1) for the specified if it's of the
@@ -1264,6 +1685,8 @@ public static class PublishedContentExtensions
///
/// The content type.
/// The content.
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
///
/// The root content (ancestor or self at level 1) for the specified of content type
/// .
@@ -1273,9 +1696,12 @@ public static class PublishedContentExtensions
/// with
/// maxLevel set to 1.
///
- public static T? Root(this IPublishedContent content)
+ public static T? Root(
+ this IPublishedContent content,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService)
where T : class, IPublishedContent =>
- content.AncestorOrSelf(1);
+ content.AncestorOrSelf(publishedCache, navigationQueryService, 1);
#endregion
@@ -1315,13 +1741,15 @@ public static class PublishedContentExtensions
public static DataTable ChildrenAsTable(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
IContentTypeService contentTypeService,
IMediaTypeService mediaTypeService,
IMemberTypeService memberTypeService,
IPublishedUrlProvider publishedUrlProvider,
string contentTypeAliasFilter = "",
string? culture = null)
- => GenerateDataTable(content, variationContextAccessor, contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
+ => GenerateDataTable(content, variationContextAccessor, publishedCache, navigationQueryService, contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
///
/// Gets the children of the content in a DataTable.
@@ -1341,6 +1769,8 @@ public static class PublishedContentExtensions
private static DataTable GenerateDataTable(
IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
+ IPublishedCache publishedCache,
+ INavigationQueryService navigationQueryService,
IContentTypeService contentTypeService,
IMediaTypeService mediaTypeService,
IMemberTypeService memberTypeService,
@@ -1349,10 +1779,10 @@ public static class PublishedContentExtensions
string? culture = null)
{
IPublishedContent? firstNode = contentTypeAliasFilter.IsNullOrWhiteSpace()
- ? content.Children(variationContextAccessor, culture)?.Any() ?? false
- ? content.Children(variationContextAccessor, culture)?.ElementAt(0)
+ ? content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.Any() ?? false
+ ? content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.ElementAt(0)
: null
- : content.Children(variationContextAccessor, culture)
+ : content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)
?.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAliasFilter));
if (firstNode == null)
{
@@ -1375,7 +1805,7 @@ public static class PublishedContentExtensions
List>, IEnumerable>>>
tableData = DataTableExtensions.CreateTableData();
IOrderedEnumerable? children =
- content.Children(variationContextAccessor)?.OrderBy(x => x.SortOrder);
+ content.Children(variationContextAccessor, publishedCache, navigationQueryService)?.OrderBy(x => x.SortOrder);
if (children is not null)
{
// loop through each child and create row data for it
diff --git a/src/Umbraco.Core/Extensions/PublishedSnapshotAccessorExtensions.cs b/src/Umbraco.Core/Extensions/PublishedSnapshotAccessorExtensions.cs
deleted file mode 100644
index 5e6d356674..0000000000
--- a/src/Umbraco.Core/Extensions/PublishedSnapshotAccessorExtensions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Umbraco.Cms.Core.PublishedCache;
-
-namespace Umbraco.Extensions;
-
-public static class PublishedSnapshotAccessorExtensions
-{
- public static IPublishedSnapshot GetRequiredPublishedSnapshot(
- this IPublishedSnapshotAccessor publishedSnapshotAccessor)
- {
- if (publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot))
- {
- return publishedSnapshot!;
- }
-
- throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot");
- }
-}
diff --git a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs
index 22bbfae7c7..233a67fa62 100644
--- a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs
+++ b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs
@@ -209,7 +209,7 @@ public static class ContentRepositoryExtensions
{
foreach (IPropertyValue pvalue in otherProperty.Values)
{
- if (((otherProperty?.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, true) ?? false) &&
+ if (((otherProperty?.PropertyType?.SupportsVariation(pvalue.Culture, pvalue.Segment, true) ?? false) &&
(culture == "*" ||(pvalue.Culture?.InvariantEquals(culture) ?? false))) ||
otherProperty?.PropertyType?.Variations == ContentVariation.Nothing)
{
diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs
index 9028a501ad..8792baaecc 100644
--- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs
@@ -100,6 +100,7 @@ public interface IPublishedContent : IPublishedElement
/// Gets the parent of the content item.
///
/// The parent of root content is null.
+ [Obsolete("Please use IDocumentNavigationQueryService.TryGetParentKey() instead. Scheduled for removal in V16.")]
IPublishedContent? Parent { get; }
///
@@ -141,10 +142,6 @@ public interface IPublishedContent : IPublishedElement
///
/// Gets the children of the content item that are available for the current culture.
///
+ [Obsolete("Please use IDocumentNavigationQueryService.TryGetChildrenKeys() instead. Scheduled for removal in V16.")]
IEnumerable Children { get; }
-
- ///
- /// Gets all the children of the content item, regardless of whether they are available for the current culture.
- ///
- IEnumerable ChildrenForAllCultures { get; }
}
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs
index c9394e1e27..56f7789578 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs
@@ -1,4 +1,8 @@
using System.Diagnostics;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Models.PublishedContent
@@ -33,9 +37,11 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
public abstract int SortOrder { get; }
///
+ [Obsolete("Not supported for members, scheduled for removal in v17")]
public abstract int Level { get; }
///
+ [Obsolete("Not supported for members, scheduled for removal in v17")]
public abstract string Path { get; }
///
@@ -66,18 +72,41 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
public abstract bool IsPublished(string? culture = null);
///
+ [Obsolete("Please use TryGetParentKey() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
public abstract IPublishedContent? Parent { get; }
+ // FIXME
///
- public virtual IEnumerable Children => this.Children(_variationContextAccessor);
+ [Obsolete("Please use TryGetChildrenKeys() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
+ public virtual IEnumerable Children => GetChildren();
- ///
- public abstract IEnumerable ChildrenForAllCultures { get; }
///
public abstract IEnumerable Properties { get; }
///
public abstract IPublishedProperty? GetProperty(string alias);
+
+ private IEnumerable GetChildren()
+ {
+ INavigationQueryService? navigationQueryService;
+ IPublishedCache? publishedCache;
+
+ switch (ContentType.ItemType)
+ {
+ case PublishedItemType.Content:
+ publishedCache = StaticServiceProvider.Instance.GetRequiredService();
+ navigationQueryService = StaticServiceProvider.Instance.GetRequiredService();
+ break;
+ case PublishedItemType.Media:
+ publishedCache = StaticServiceProvider.Instance.GetRequiredService();
+ navigationQueryService = StaticServiceProvider.Instance.GetRequiredService();
+ break;
+ default:
+ throw new NotImplementedException("Level is not implemented for " + ContentType.ItemType);
+ }
+
+ return this.Children(_variationContextAccessor, publishedCache, navigationQueryService);
+ }
}
}
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs
index ddeff558dd..807943edff 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs
@@ -1,4 +1,9 @@
using System.Diagnostics;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
+using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Models.PublishedContent;
@@ -90,6 +95,7 @@ public abstract class PublishedContentWrapped : IPublishedContent
public virtual PublishedItemType ItemType => _content.ItemType;
///
+ [Obsolete("Please use TryGetParentKey() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
public virtual IPublishedContent? Parent => _content.Parent;
///
@@ -99,11 +105,9 @@ public abstract class PublishedContentWrapped : IPublishedContent
public virtual bool IsPublished(string? culture = null) => _content.IsPublished(culture);
///
+ [Obsolete("Please use TryGetChildrenKeys() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
public virtual IEnumerable Children => _content.Children;
- ///
- public virtual IEnumerable ChildrenForAllCultures => _content.ChildrenForAllCultures;
-
///
public virtual IEnumerable Properties => _content.Properties;
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
index 8a50323f12..bec5250e01 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
@@ -1,4 +1,8 @@
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Models.PublishedContent;
@@ -184,7 +188,7 @@ public class PublishedValueFallback : IPublishedValueFallback
IPublishedProperty? property; // if we are here, content's property has no value
do
{
- content = content?.Parent;
+ content = content?.Parent(StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService());
IPublishedPropertyType? propertyType = content?.ContentType.GetPropertyType(alias);
diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs
index 014a0a1a8c..6fdf5d3246 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs
@@ -12,17 +12,14 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
public class MemberPickerValueConverter : PropertyValueConverterBase, IDeliveryApiPropertyValueConverter
{
private readonly IMemberService _memberService;
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
- private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IPublishedMemberCache _memberCache;
public MemberPickerValueConverter(
IMemberService memberService,
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
- IUmbracoContextAccessor umbracoContextAccessor)
+ IPublishedMemberCache memberCache)
{
_memberService = memberService;
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
- _umbracoContextAccessor = umbracoContextAccessor;
+ _memberCache = memberCache;
}
public override bool IsConverter(IPublishedPropertyType propertyType)
@@ -64,7 +61,6 @@ public class MemberPickerValueConverter : PropertyValueConverterBase, IDeliveryA
}
IPublishedContent? member;
- IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
if (source is int id)
{
IMember? m = _memberService.GetById(id);
@@ -73,7 +69,7 @@ public class MemberPickerValueConverter : PropertyValueConverterBase, IDeliveryA
return null;
}
- member = publishedSnapshot?.Members?.Get(m);
+ member = _memberCache.Get(m);
if (member != null)
{
return member;
@@ -92,7 +88,7 @@ public class MemberPickerValueConverter : PropertyValueConverterBase, IDeliveryA
return null;
}
- member = publishedSnapshot?.Members?.Get(m);
+ member = _memberCache.Get(m);
if (member != null)
{
diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
index 2d4060a89d..22e3067244 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs
@@ -25,24 +25,29 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
};
private readonly IMemberService _memberService;
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IApiContentBuilder _apiContentBuilder;
private readonly IApiMediaBuilder _apiMediaBuilder;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IPublishedMediaCache _mediaCache;
+ private readonly IPublishedMemberCache _memberCache;
public MultiNodeTreePickerValueConverter(
- IPublishedSnapshotAccessor publishedSnapshotAccessor,
IUmbracoContextAccessor umbracoContextAccessor,
IMemberService memberService,
IApiContentBuilder apiContentBuilder,
- IApiMediaBuilder apiMediaBuilder)
+ IApiMediaBuilder apiMediaBuilder,
+ IPublishedContentCache contentCache,
+ IPublishedMediaCache mediaCache,
+ IPublishedMemberCache memberCache)
{
- _publishedSnapshotAccessor = publishedSnapshotAccessor ??
- throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
_umbracoContextAccessor = umbracoContextAccessor;
_memberService = memberService;
_apiContentBuilder = apiContentBuilder;
_apiMediaBuilder = apiMediaBuilder;
+ _contentCache = contentCache;
+ _mediaCache = mediaCache;
+ _memberCache = memberCache;
}
public override bool IsConverter(IPublishedPropertyType propertyType) =>
@@ -95,7 +100,6 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
var multiNodeTreePicker = new List();
UmbracoObjectTypes objectType = UmbracoObjectTypes.Unknown;
- IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
foreach (Udi udi in udis)
{
if (udi is not GuidUdi guidUdi)
@@ -111,14 +115,14 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
udi,
ref objectType,
UmbracoObjectTypes.Document,
- id => publishedSnapshot.Content?.GetById(guidUdi.Guid));
+ id => _contentCache.GetById(guidUdi.Guid));
break;
case Constants.UdiEntityType.Media:
multiNodeTreePickerItem = GetPublishedContent(
udi,
ref objectType,
UmbracoObjectTypes.Media,
- id => publishedSnapshot.Media?.GetById(guidUdi.Guid));
+ id => _mediaCache.GetById(guidUdi.Guid));
break;
case Constants.UdiEntityType.Member:
multiNodeTreePickerItem = GetPublishedContent(
@@ -133,7 +137,7 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
return null;
}
- IPublishedContent? member = publishedSnapshot?.Members?.Get(m);
+ IPublishedContent? member = _memberCache.Get(m);
return member;
});
break;
@@ -188,8 +192,6 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
return DefaultValue();
}
- IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
-
var entityType = GetEntityType(propertyType);
if (entityType == "content")
@@ -203,14 +205,14 @@ public class MultiNodeTreePickerValueConverter : PropertyValueConverterBase, IDe
{
Constants.UdiEntityType.Document => entityTypeUdis.Select(udi =>
{
- IPublishedContent? content = publishedSnapshot.Content?.GetById(udi.Guid);
+ IPublishedContent? content = _contentCache.GetById(udi.Guid);
return content != null
? _apiContentBuilder.Build(content)
: null;
}).WhereNotNull().ToArray(),
Constants.UdiEntityType.Media => entityTypeUdis.Select(udi =>
{
- IPublishedContent? media = publishedSnapshot.Media?.GetById(udi.Guid);
+ IPublishedContent? media = _mediaCache.GetById(udi.Guid);
return media != null
? _apiMediaBuilder.Build(media)
: null;
diff --git a/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs b/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs
new file mode 100644
index 0000000000..4eac53dc03
--- /dev/null
+++ b/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs
@@ -0,0 +1,6 @@
+namespace Umbraco.Cms.Core.PublishedCache;
+
+public interface IDatabaseCacheRebuilder
+{
+ void Rebuild();
+}
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedCache.cs b/src/Umbraco.Core/PublishedCache/IPublishedCache.cs
index e4d8a2311c..2a8809deb6 100644
--- a/src/Umbraco.Core/PublishedCache/IPublishedCache.cs
+++ b/src/Umbraco.Core/PublishedCache/IPublishedCache.cs
@@ -67,7 +67,7 @@ public interface IPublishedCache
/// A culture.
/// The contents.
/// The value of overrides defaults.
- [Obsolete] // FIXME: Remove when replacing nucache
+ [Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
IEnumerable GetAtRoot(bool preview, string? culture = null);
///
@@ -76,7 +76,7 @@ public interface IPublishedCache
/// A culture.
/// The contents.
/// Considers published or unpublished content depending on defaults.
- [Obsolete] // FIXME: Remove when replacing nucache
+ [Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
IEnumerable GetAtRoot(string? culture = null);
///
@@ -85,7 +85,7 @@ public interface IPublishedCache
/// A value indicating whether to consider unpublished content.
/// A value indicating whether the cache contains published content.
/// The value of overrides defaults.
- [Obsolete] // FIXME: Remove when replacing nucache
+ [Obsolete("Scheduled for removal in v17")]
bool HasContent(bool preview);
///
@@ -93,7 +93,7 @@ public interface IPublishedCache
///
/// A value indicating whether the cache contains published content.
/// Considers published or unpublished content depending on defaults.
- [Obsolete] // FIXME: Remove when replacing nucache
+ [Obsolete("Scheduled for removal in v17")]
bool HasContent();
///
@@ -118,7 +118,7 @@ public interface IPublishedCache
///
/// The content type.
/// The contents.
- [Obsolete] // FIXME: Remove when replacing nucache
+ [Obsolete]
IEnumerable GetByContentType(IPublishedContentType contentType);
///
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshot.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshot.cs
deleted file mode 100644
index 43e6291701..0000000000
--- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshot.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using Umbraco.Cms.Core.Cache;
-
-namespace Umbraco.Cms.Core.PublishedCache;
-
-///
-/// Specifies a published snapshot.
-///
-///
-/// A published snapshot is a point-in-time capture of the current state of
-/// everything that is "published".
-///
-public interface IPublishedSnapshot : IDisposable
-{
- ///
- /// Gets the .
- ///
- IPublishedContentCache? Content { get; }
-
- ///
- /// Gets the .
- ///
- IPublishedMediaCache? Media { get; }
-
- ///
- /// Gets the .
- ///
- IPublishedMemberCache? Members { get; }
-
- ///
- /// Gets the .
- ///
- IDomainCache? Domains { get; }
-
- ///
- /// Gets the snapshot-level cache.
- ///
- ///
- /// The snapshot-level cache belongs to this snapshot only.
- ///
- IAppCache? SnapshotCache { get; }
-
- ///
- /// Gets the elements-level cache.
- ///
- ///
- ///
- /// The elements-level cache is shared by all snapshots relying on the same elements,
- /// ie all snapshots built on top of unchanging content / media / etc.
- ///
- ///
- IAppCache? ElementsCache { get; }
-
- ///
- /// Forces the preview mode.
- ///
- /// The forced preview mode.
- /// A callback to execute when reverting to previous preview.
- ///
- ///
- /// Forcing to false means no preview. Forcing to true means 'full' preview if the snapshot is not already
- /// previewing;
- /// otherwise the snapshot keeps previewing according to whatever settings it is using already.
- ///
- /// Stops forcing preview when disposed.
- ///
- IDisposable ForcedPreview(bool preview, Action? callback = null);
-}
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs
deleted file mode 100644
index 8abc0906ce..0000000000
--- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotAccessor.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Umbraco.Cms.Core.PublishedCache;
-
-///
-/// Provides access to a TryGetPublishedSnapshot bool method that will return true if the "current"
-/// is not null.
-///
-public interface IPublishedSnapshotAccessor
-{
- bool TryGetPublishedSnapshot([NotNullWhen(true)] out IPublishedSnapshot? publishedSnapshot);
-}
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs
deleted file mode 100644
index 8e661aa758..0000000000
--- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using Umbraco.Cms.Core.Cache;
-
-namespace Umbraco.Cms.Core.PublishedCache;
-
-///
-/// Creates and manages instances.
-///
-public interface IPublishedSnapshotService : IDisposable
-{
- /* Various places (such as Node) want to access the XML content, today as an XmlDocument
- * but to migrate to a new cache, they're migrating to an XPathNavigator. Still, they need
- * to find out how to get that navigator.
- *
- * Because a cache such as NuCache is contextual i.e. it has a "snapshot" thing and remains
- * consistent over the snapshot, the navigator has to come from the "current" snapshot.
- *
- * So although everything should be injected... we also need a notion of "the current published
- * snapshot". This is provided by the IPublishedSnapshotAccessor.
- *
- */
-
- ///
- /// Creates a published snapshot.
- ///
- /// A preview token, or null if not previewing.
- /// A published snapshot.
- ///
- /// If is null, the snapshot is not previewing, else it
- /// is previewing, and what is or is not visible in preview depends on the content of the token,
- /// which is not specified and depends on the actual published snapshot service implementation.
- ///
- IPublishedSnapshot CreatePublishedSnapshot(string? previewToken);
-
- ///
- /// Rebuilds internal database caches (but does not reload).
- ///
- ///
- /// If not null will process content for the matching content types, if empty will process all
- /// content
- ///
- ///
- /// If not null will process content for the matching media types, if empty will process all
- /// media
- ///
- ///
- /// If not null will process content for the matching members types, if empty will process all
- /// members
- ///
- ///
- ///
- /// Forces the snapshot service to rebuild its internal database caches. For instance, some caches
- /// may rely on a database table to store pre-serialized version of documents.
- ///
- ///
- /// This does *not* reload the caches. Caches need to be reloaded, for instance via
- /// RefreshAllPublishedSnapshot method.
- ///
- ///
- void Rebuild(
- IReadOnlyCollection? contentTypeIds = null,
- IReadOnlyCollection? mediaTypeIds = null,
- IReadOnlyCollection? memberTypeIds = null);
-
-
- ///
- /// Rebuilds all internal database caches (but does not reload).
- ///
- ///
- ///
- /// Forces the snapshot service to rebuild its internal database caches. For instance, some caches
- /// may rely on a database table to store pre-serialized version of documents.
- ///
- ///
- /// This does *not* reload the caches. Caches need to be reloaded, for instance via
- /// RefreshAllPublishedSnapshot method.
- ///
- ///
- void RebuildAll() => Rebuild(Array.Empty(), Array.Empty(), Array.Empty());
-
- /* An IPublishedCachesService implementation can rely on transaction-level events to update
- * its internal, database-level data, as these events are purely internal. However, it cannot
- * rely on cache refreshers CacheUpdated events to update itself, as these events are external
- * and the order-of-execution of the handlers cannot be guaranteed, which means that some
- * user code may run before Umbraco is finished updating itself. Instead, the cache refreshers
- * explicitly notify the service of changes.
- *
- */
-
- ///
- /// Notifies of content cache refresher changes.
- ///
- /// The changes.
- /// A value indicating whether draft contents have been changed in the cache.
- /// A value indicating whether published contents have been changed in the cache.
- void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged);
-
- ///
- /// Notifies of media cache refresher changes.
- ///
- /// The changes.
- /// A value indicating whether medias have been changed in the cache.
- void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged);
-
- // there is no NotifyChanges for MemberCacheRefresher because we're not caching members.
-
- ///
- /// Notifies of content type refresher changes.
- ///
- /// The changes.
- void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads);
-
- ///
- /// Notifies of data type refresher changes.
- ///
- /// The changes.
- void Notify(DataTypeCacheRefresher.JsonPayload[] payloads);
-
- ///
- /// Notifies of domain refresher changes.
- ///
- /// The changes.
- void Notify(DomainCacheRefresher.JsonPayload[] payloads);
-
- ///
- /// Cleans up unused snapshots
- ///
- Task CollectAsync();
-
- void ResetLocalDb()
- {
- }
-}
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs
deleted file mode 100644
index 1ae08cc42d..0000000000
--- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Umbraco.Cms.Core.PublishedCache;
-
-///
-/// Returns the currents status for nucache
-///
-public interface IPublishedSnapshotStatus
-{
- ///
- /// Gets the status report as a string
- ///
- string GetStatus();
-}
diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs
index f4e381d3a1..f8bffbba77 100644
--- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs
+++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs
@@ -1,5 +1,8 @@
using System.ComponentModel;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PublishedCache.Internal;
@@ -66,13 +69,18 @@ public sealed class InternalPublishedContent : IPublishedContent
public PublishedItemType ItemType => PublishedItemType.Content;
- public IPublishedContent? Parent { get; set; }
+ [Obsolete("Please use TryGetParentKey() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
+ public IPublishedContent? Parent => this.Parent(StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService());
public bool IsDraft(string? culture = null) => false;
public bool IsPublished(string? culture = null) => true;
- public IEnumerable Children { get; set; } = Enumerable.Empty();
+ [Obsolete("Please use TryGetChildrenKeys() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
+ public IEnumerable Children => this.Children(
+ StaticServiceProvider.Instance.GetRequiredService(),
+ StaticServiceProvider.Instance.GetRequiredService(),
+ StaticServiceProvider.Instance.GetRequiredService());
public IEnumerable ChildrenForAllCultures => Children;
@@ -94,7 +102,7 @@ public sealed class InternalPublishedContent : IPublishedContent
IPublishedContent? content = this;
while (content != null && (property == null || property.HasValue() == false))
{
- content = content.Parent;
+ content = content.Parent(StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService());
property = content?.GetProperty(alias);
}
diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs
deleted file mode 100644
index 5b57236d4f..0000000000
--- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System.ComponentModel;
-using Umbraco.Cms.Core.Models.PublishedContent;
-
-namespace Umbraco.Cms.Core.PublishedCache.Internal;
-
-// TODO: Only used in unit tests, needs to be moved to test project
-[EditorBrowsable(EditorBrowsableState.Never)]
-public sealed class InternalPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache
-{
- private readonly Dictionary _content = new();
-
- public InternalPublishedContentCache()
- : base(false)
- {
- }
-
- public Task GetByIdAsync(int id, bool preview = false) => throw new NotImplementedException();
-
- public Task GetByIdAsync(Guid key, bool preview = false) => throw new NotImplementedException();
-
- public Task HasByIdAsync(int id, bool preview = false) => throw new NotImplementedException();
-
- public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string? culture = null) => throw new NotImplementedException();
-
- public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string? culture = null) =>
- throw new NotImplementedException();
-
- public string GetRouteById(bool preview, int contentId, string? culture = null) =>
- throw new NotImplementedException();
-
- public string GetRouteById(int contentId, string? culture = null) => throw new NotImplementedException();
-
- public override IPublishedContent? GetById(bool preview, int contentId) =>
- _content.ContainsKey(contentId) ? _content[contentId] : null;
-
- public override IPublishedContent GetById(bool preview, Guid contentId) => throw new NotImplementedException();
-
- public override IPublishedContent GetById(bool preview, Udi nodeId) => throw new NotSupportedException();
-
- public override bool HasById(bool preview, int contentId) => _content.ContainsKey(contentId);
-
- public override IEnumerable GetAtRoot(bool preview, string? culture = null) =>
- _content.Values.Where(x => x.Parent == null);
-
- public override bool HasContent(bool preview) => _content.Count > 0;
-
- public override IPublishedContentType GetContentType(int id) => throw new NotImplementedException();
-
- public override IPublishedContentType GetContentType(string alias) => throw new NotImplementedException();
-
- public override IPublishedContentType GetContentType(Guid key) => throw new NotImplementedException();
-
- public override IEnumerable GetByContentType(IPublishedContentType contentType) =>
- throw new NotImplementedException();
-
- // public void Add(InternalPublishedContent content) => _content[content.Id] = content.CreateModel(Mock.Of());
- public void Clear() => _content.Clear();
- public Task GetByIdAsync(int id) => throw new NotImplementedException();
-
- public Task GetByKeyAsync(Guid key) => throw new NotImplementedException();
-
- public Task HasByIdAsync(int id) => throw new NotImplementedException();
-}
diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs
deleted file mode 100644
index 015962b5aa..0000000000
--- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.ComponentModel;
-using Umbraco.Cms.Core.Cache;
-
-namespace Umbraco.Cms.Core.PublishedCache.Internal;
-
-// TODO: Only used in unit tests, needs to be moved to test project
-[EditorBrowsable(EditorBrowsableState.Never)]
-public sealed class InternalPublishedSnapshot : IPublishedSnapshot
-{
- public InternalPublishedContentCache InnerContentCache { get; } = new();
-
- public InternalPublishedContentCache InnerMediaCache { get; } = new();
-
- public IPublishedContentCache Content => InnerContentCache;
-
- public IPublishedMediaCache Media => InnerMediaCache;
-
- public IPublishedMemberCache? Members => null;
-
- public IDomainCache? Domains => null;
-
- public IAppCache? SnapshotCache => null;
-
- public IDisposable ForcedPreview(bool forcedPreview, Action? callback = null) =>
- throw new NotImplementedException();
-
- public IAppCache? ElementsCache => null;
-
- public void Dispose()
- {
- }
-
- public void Resync()
- {
- }
-}
diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs
deleted file mode 100644
index 09de76ace5..0000000000
--- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System.ComponentModel;
-using Umbraco.Cms.Core.Cache;
-using Umbraco.Extensions;
-
-namespace Umbraco.Cms.Core.PublishedCache.Internal;
-
-// TODO: Only used in unit tests, needs to be moved to test project
-[EditorBrowsable(EditorBrowsableState.Never)]
-public class InternalPublishedSnapshotService : IPublishedSnapshotService
-{
- private InternalPublishedSnapshot? _previewSnapshot;
- private InternalPublishedSnapshot? _snapshot;
-
- public Task CollectAsync() => Task.CompletedTask;
-
- public IPublishedSnapshot CreatePublishedSnapshot(string? previewToken)
- {
- if (previewToken.IsNullOrWhiteSpace())
- {
- return _snapshot ??= new InternalPublishedSnapshot();
- }
-
- return _previewSnapshot ??= new InternalPublishedSnapshot();
- }
-
- public void Dispose()
- {
- _snapshot?.Dispose();
- _previewSnapshot?.Dispose();
- }
-
- public void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged)
- {
- draftChanged = false;
- publishedChanged = false;
- }
-
- public void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) => anythingChanged = false;
-
- public void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads)
- {
- }
-
- public void Notify(DataTypeCacheRefresher.JsonPayload[] payloads)
- {
- }
-
- public void Notify(DomainCacheRefresher.JsonPayload[] payloads)
- {
- }
-
- public void Rebuild(IReadOnlyCollection? contentTypeIds = null, IReadOnlyCollection? mediaTypeIds = null, IReadOnlyCollection? memberTypeIds = null)
- {
- }
-}
diff --git a/src/Umbraco.Core/PublishedCache/PublishedCacheBase.cs b/src/Umbraco.Core/PublishedCache/PublishedCacheBase.cs
index 88acd5d29c..2abba65d4a 100644
--- a/src/Umbraco.Core/PublishedCache/PublishedCacheBase.cs
+++ b/src/Umbraco.Core/PublishedCache/PublishedCacheBase.cs
@@ -64,11 +64,5 @@ public abstract class PublishedCacheBase : IPublishedCache
public abstract IPublishedContentType? GetContentType(Guid key);
- public virtual IEnumerable GetByContentType(IPublishedContentType contentType) =>
-
- // this is probably not super-efficient, but works
- // some cache implementation may want to override it, though
- GetAtRoot()
- .SelectMany(x => x.DescendantsOrSelf(_variationContextAccessor!))
- .Where(x => x.ContentType.Id == contentType.Id);
+ public virtual IEnumerable GetByContentType(IPublishedContentType contentType) => throw new NotImplementedException();
}
diff --git a/src/Umbraco.Core/PublishedCache/PublishedElement.cs b/src/Umbraco.Core/PublishedCache/PublishedElement.cs
index 297a62b589..92d8646539 100644
--- a/src/Umbraco.Core/PublishedCache/PublishedElement.cs
+++ b/src/Umbraco.Core/PublishedCache/PublishedElement.cs
@@ -18,7 +18,7 @@ public class PublishedElement : IPublishedElement
// initializes a new instance of the PublishedElement class
// within the context of a published snapshot service (eg a published content property value)
- public PublishedElement(IPublishedContentType contentType, Guid key, Dictionary? values, bool previewing, PropertyCacheLevel referenceCacheLevel, IPublishedSnapshotAccessor? publishedSnapshotAccessor)
+ public PublishedElement(IPublishedContentType contentType, Guid key, Dictionary? values, bool previewing, PropertyCacheLevel referenceCacheLevel, ICacheManager? cacheManager)
{
if (key == Guid.Empty)
{
@@ -30,13 +30,6 @@ public class PublishedElement : IPublishedElement
throw new ArgumentNullException(nameof(values));
}
- if (referenceCacheLevel != PropertyCacheLevel.None && publishedSnapshotAccessor == null)
- {
- throw new ArgumentNullException(
- "A published snapshot accessor is required when referenceCacheLevel != None.",
- nameof(publishedSnapshotAccessor));
- }
-
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
Key = key;
@@ -47,7 +40,7 @@ public class PublishedElement : IPublishedElement
.Select(propertyType =>
{
values.TryGetValue(propertyType.Alias, out var value);
- return (IPublishedProperty)new PublishedElementPropertyBase(propertyType, this, previewing, referenceCacheLevel, value, publishedSnapshotAccessor);
+ return (IPublishedProperty)new PublishedElementPropertyBase(propertyType, this, previewing, referenceCacheLevel,cacheManager, value);
})
.ToArray()
?? new IPublishedProperty[0];
diff --git a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs
index 53e8156538..0452cf0b03 100644
--- a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs
+++ b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs
@@ -15,10 +15,10 @@ internal class PublishedElementPropertyBase : PublishedPropertyBase
// so making it configurable.
private const bool FullCacheWhenPreviewing = true;
private readonly object _locko = new();
- private readonly IPublishedSnapshotAccessor? _publishedSnapshotAccessor;
private readonly object? _sourceValue;
protected readonly bool IsMember;
protected readonly bool IsPreviewing;
+ private readonly ICacheManager? _cacheManager;
private CacheValues? _cacheValues;
private bool _interInitialized;
@@ -30,14 +30,14 @@ internal class PublishedElementPropertyBase : PublishedPropertyBase
IPublishedElement element,
bool previewing,
PropertyCacheLevel referenceCacheLevel,
- object? sourceValue = null,
- IPublishedSnapshotAccessor? publishedSnapshotAccessor = null)
+ ICacheManager? cacheManager,
+ object? sourceValue = null)
: base(propertyType, referenceCacheLevel)
{
_sourceValue = sourceValue;
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
Element = element;
IsPreviewing = previewing;
+ _cacheManager = cacheManager;
IsMember = propertyType.ContentType?.ItemType == PublishedItemType.Member;
}
@@ -118,33 +118,13 @@ internal class PublishedElementPropertyBase : PublishedPropertyBase
}
}
- private IAppCache? GetSnapshotCache()
- {
- // cache within the snapshot cache, unless previewing, then use the snapshot or
- // 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
- if (_publishedSnapshotAccessor is null)
- {
- return null;
- }
-
- if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot))
- {
- return null;
- }
-
- return (IsPreviewing == false || FullCacheWhenPreviewing) && IsMember == false
- ? publishedSnapshot!.ElementsCache
- : publishedSnapshot!.SnapshotCache;
- }
-
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
{
CacheValues cacheValues;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
+ case PropertyCacheLevel.Snapshot:
// never cache anything
cacheValues = new CacheValues();
break;
@@ -153,17 +133,7 @@ internal class PublishedElementPropertyBase : PublishedPropertyBase
cacheValues = _cacheValues ??= new CacheValues();
break;
case PropertyCacheLevel.Elements:
- // cache within the elements cache, depending...
- IAppCache? snapshotCache = GetSnapshotCache();
- cacheValues = (CacheValues?)snapshotCache?.Get(ValuesCacheKey, () => new CacheValues()) ??
- new CacheValues();
- break;
- case PropertyCacheLevel.Snapshot:
- IPublishedSnapshot? publishedSnapshot = _publishedSnapshotAccessor?.GetRequiredPublishedSnapshot();
-
- // cache within the snapshot cache
- IAppCache? facadeCache = publishedSnapshot?.SnapshotCache;
- cacheValues = (CacheValues?)facadeCache?.Get(ValuesCacheKey, () => new CacheValues()) ??
+ cacheValues = (CacheValues?)_cacheManager?.ElementsCache.Get(ValuesCacheKey, () => new CacheValues()) ??
new CacheValues();
break;
default:
diff --git a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs b/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs
deleted file mode 100644
index 91e32e6db4..0000000000
--- a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using Umbraco.Cms.Core.Web;
-
-namespace Umbraco.Cms.Core.PublishedCache;
-
-// TODO: This is a mess. This is a circular reference:
-// IPublishedSnapshotAccessor -> PublishedSnapshotService -> UmbracoContext -> PublishedSnapshotService -> IPublishedSnapshotAccessor
-// Injecting IPublishedSnapshotAccessor into PublishedSnapshotService seems pretty strange
-// The underlying reason for this mess is because IPublishedContent is both a service and a model.
-// Until that is fixed, IPublishedContent will need to have a IPublishedSnapshotAccessor
-public class UmbracoContextPublishedSnapshotAccessor : IPublishedSnapshotAccessor
-{
- private readonly IUmbracoContextAccessor _umbracoContextAccessor;
-
- public UmbracoContextPublishedSnapshotAccessor(IUmbracoContextAccessor umbracoContextAccessor) =>
- _umbracoContextAccessor = umbracoContextAccessor;
-
- public IPublishedSnapshot? PublishedSnapshot
- {
- get
- {
- if (!_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext))
- {
- return null;
- }
-
- return umbracoContext?.PublishedSnapshot;
- }
-
- set => throw new NotSupportedException(); // not ok to set
- }
-
- public bool TryGetPublishedSnapshot([NotNullWhen(true)] out IPublishedSnapshot? publishedSnapshot)
- {
- if (!_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext))
- {
- publishedSnapshot = null;
- return false;
- }
-
- publishedSnapshot = umbracoContext?.PublishedSnapshot;
-
- return publishedSnapshot is not null;
- }
-}
diff --git a/src/Umbraco.Core/Routing/AliasUrlProvider.cs b/src/Umbraco.Core/Routing/AliasUrlProvider.cs
index 65d9387e2e..59e9e1d381 100644
--- a/src/Umbraco.Core/Routing/AliasUrlProvider.cs
+++ b/src/Umbraco.Core/Routing/AliasUrlProvider.cs
@@ -1,6 +1,10 @@
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
@@ -14,6 +18,8 @@ public class AliasUrlProvider : IUrlProvider
private readonly IPublishedValueFallback _publishedValueFallback;
private readonly ISiteDomainMapper _siteDomainMapper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
private readonly UriUtility _uriUtility;
private RequestHandlerSettings _requestConfig;
@@ -22,17 +28,39 @@ public class AliasUrlProvider : IUrlProvider
ISiteDomainMapper siteDomainMapper,
UriUtility uriUtility,
IPublishedValueFallback publishedValueFallback,
- IUmbracoContextAccessor umbracoContextAccessor)
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService navigationQueryService)
{
_requestConfig = requestConfig.CurrentValue;
_siteDomainMapper = siteDomainMapper;
_uriUtility = uriUtility;
_publishedValueFallback = publishedValueFallback;
_umbracoContextAccessor = umbracoContextAccessor;
+ _contentCache = contentCache;
+ _navigationQueryService = navigationQueryService;
requestConfig.OnChange(x => _requestConfig = x);
}
+ [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
+ public AliasUrlProvider(
+ IOptionsMonitor requestConfig,
+ ISiteDomainMapper siteDomainMapper,
+ UriUtility uriUtility,
+ IPublishedValueFallback publishedValueFallback,
+ IUmbracoContextAccessor umbracoContextAccessor)
+ : this(
+ requestConfig,
+ siteDomainMapper,
+ uriUtility,
+ publishedValueFallback,
+ umbracoContextAccessor,
+ StaticServiceProvider.Instance.GetRequiredService(),
+ StaticServiceProvider.Instance.GetRequiredService())
+ {
+ }
+
// note - at the moment we seem to accept pretty much anything as an alias
// without any form of validation ... could even prob. kill the XPath ...
// ok, this is somewhat experimental and is NOT enabled by default
@@ -74,16 +102,16 @@ public class AliasUrlProvider : IUrlProvider
// look for domains, walking up the tree
IPublishedContent? n = node;
- IEnumerable? domainUris = DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current, false);
+ IEnumerable? domainUris = DomainUtilities.DomainsForNode(umbracoContext.Domains, _siteDomainMapper, n.Id, current, false);
// n is null at root
while (domainUris == null && n != null)
{
// move to parent node
- n = n.Parent;
+ n = n.Parent(_contentCache, _navigationQueryService);
domainUris = n == null
? null
- : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current, false);
+ : DomainUtilities.DomainsForNode(umbracoContext.Domains, _siteDomainMapper, n.Id, current, false);
}
// determine whether the alias property varies
diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
index 3a04c2cb5b..f592fb0a0f 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
@@ -21,6 +22,8 @@ public class ContentFinderByUrlAlias : IContentFinder
private readonly ILogger _logger;
private readonly IPublishedValueFallback _publishedValueFallback;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
private readonly IVariationContextAccessor _variationContextAccessor;
///
@@ -30,11 +33,15 @@ public class ContentFinderByUrlAlias : IContentFinder
ILogger logger,
IPublishedValueFallback publishedValueFallback,
IVariationContextAccessor variationContextAccessor,
- IUmbracoContextAccessor umbracoContextAccessor)
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService documentNavigationQueryService)
{
_publishedValueFallback = publishedValueFallback;
_variationContextAccessor = variationContextAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
+ _contentCache = contentCache;
+ _documentNavigationQueryService = documentNavigationQueryService;
_logger = logger;
}
@@ -138,14 +145,14 @@ public class ContentFinderByUrlAlias : IContentFinder
if (rootNodeId > 0)
{
IPublishedContent? rootNode = cache?.GetById(rootNodeId);
- return rootNode?.Descendants(_variationContextAccessor).FirstOrDefault(x => IsMatch(x, test1, test2));
+ return rootNode?.Descendants(_variationContextAccessor, _contentCache, _documentNavigationQueryService).FirstOrDefault(x => IsMatch(x, test1, test2));
}
if (cache is not null)
{
foreach (IPublishedContent rootContent in cache.GetAtRoot())
{
- IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor)
+ IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor, _contentCache, _documentNavigationQueryService)
.FirstOrDefault(x => IsMatch(x, test1, test2));
if (c != null)
{
diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
index 4a5d5d2826..72f1dac37e 100644
--- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
+++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
@@ -5,7 +5,9 @@ using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
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.Core.Web;
using Umbraco.Extensions;
@@ -21,27 +23,53 @@ public class DefaultUrlProvider : IUrlProvider
private readonly ILogger _logger;
private readonly ISiteDomainMapper _siteDomainMapper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
private readonly UriUtility _uriUtility;
private RequestHandlerSettings _requestSettings;
- public DefaultUrlProvider(
- IOptionsMonitor requestSettings,
- ILogger logger,
- ISiteDomainMapper siteDomainMapper,
- IUmbracoContextAccessor umbracoContextAccessor,
- UriUtility uriUtility,
- ILocalizationService localizationService)
- {
- _requestSettings = requestSettings.CurrentValue;
- _logger = logger;
- _siteDomainMapper = siteDomainMapper;
- _umbracoContextAccessor = umbracoContextAccessor;
- _uriUtility = uriUtility;
- _localizationService = localizationService;
+ public DefaultUrlProvider(
+ IOptionsMonitor requestSettings,
+ ILogger logger,
+ ISiteDomainMapper siteDomainMapper,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ UriUtility uriUtility,
+ ILocalizationService localizationService,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService navigationQueryService)
+ {
+ _requestSettings = requestSettings.CurrentValue;
+ _logger = logger;
+ _siteDomainMapper = siteDomainMapper;
+ _umbracoContextAccessor = umbracoContextAccessor;
+ _uriUtility = uriUtility;
+ _localizationService = localizationService;
+ _contentCache = contentCache;
+ _navigationQueryService = navigationQueryService;
requestSettings.OnChange(x => _requestSettings = x);
}
+ [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
+ public DefaultUrlProvider(
+ IOptionsMonitor requestSettings,
+ ILogger logger,
+ ISiteDomainMapper siteDomainMapper,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ UriUtility uriUtility,
+ ILocalizationService localizationService)
+ : this(
+ requestSettings,
+ logger,
+ siteDomainMapper,
+ umbracoContextAccessor,
+ uriUtility,
+ localizationService,
+ StaticServiceProvider.Instance.GetRequiredService(),
+ StaticServiceProvider.Instance.GetRequiredService())
+ {
+ }
+
#region GetOtherUrls
///
@@ -68,15 +96,15 @@ public class DefaultUrlProvider : IUrlProvider
// look for domains, walking up the tree
IPublishedContent? n = node;
IEnumerable? domainUris =
- DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current, false);
+ DomainUtilities.DomainsForNode(umbracoContext.Domains, _siteDomainMapper, n.Id, current, false);
// n is null at root
while (domainUris == null && n != null)
{
- n = n.Parent; // move to parent node
+ n = n.Parent(_contentCache, _navigationQueryService); // move to parent node
domainUris = n == null
? null
- : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current);
+ : DomainUtilities.DomainsForNode(umbracoContext.Domains, _siteDomainMapper, n.Id, current);
}
// no domains = exit
@@ -152,7 +180,7 @@ public class DefaultUrlProvider : IUrlProvider
DomainAndUri? domainUri = pos == 0
? null
: DomainUtilities.DomainForNode(
- umbracoContext.PublishedSnapshot.Domains,
+ umbracoContext.Domains,
_siteDomainMapper,
int.Parse(route[..pos], CultureInfo.InvariantCulture),
current,
diff --git a/src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs b/src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs
index c4fa6cfe1d..4e636a3f9e 100644
--- a/src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs
+++ b/src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs
@@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Models;
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.Core.Web;
using Umbraco.Extensions;
@@ -21,6 +22,7 @@ public class NewDefaultUrlProvider : IUrlProvider
private readonly IDomainCache _domainCache;
private readonly IIdKeyMap _idKeyMap;
private readonly IDocumentUrlService _documentUrlService;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
private readonly ILocalizedTextService? _localizedTextService;
private readonly ILogger _logger;
private readonly ISiteDomainMapper _siteDomainMapper;
@@ -28,30 +30,32 @@ public class NewDefaultUrlProvider : IUrlProvider
private readonly UriUtility _uriUtility;
private RequestHandlerSettings _requestSettings;
- public NewDefaultUrlProvider(
- IOptionsMonitor requestSettings,
- ILogger logger,
- ISiteDomainMapper siteDomainMapper,
- IUmbracoContextAccessor umbracoContextAccessor,
- UriUtility uriUtility,
- ILocalizationService localizationService,
- IPublishedContentCache publishedContentCache,
- IDomainCache domainCache,
- IIdKeyMap idKeyMap,
- IDocumentUrlService documentUrlService)
- {
- _requestSettings = requestSettings.CurrentValue;
- _logger = logger;
- _siteDomainMapper = siteDomainMapper;
- _umbracoContextAccessor = umbracoContextAccessor;
- _uriUtility = uriUtility;
- _localizationService = localizationService;
- _publishedContentCache = publishedContentCache;
- _domainCache = domainCache;
- _idKeyMap = idKeyMap;
- _documentUrlService = documentUrlService;
+ public NewDefaultUrlProvider(
+ IOptionsMonitor requestSettings,
+ ILogger logger,
+ ISiteDomainMapper siteDomainMapper,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ UriUtility uriUtility,
+ ILocalizationService localizationService,
+ IPublishedContentCache publishedContentCache,
+ IDomainCache domainCache,
+ IIdKeyMap idKeyMap,
+ IDocumentUrlService documentUrlService,
+ IDocumentNavigationQueryService navigationQueryService)
+ {
+ _requestSettings = requestSettings.CurrentValue;
+ _logger = logger;
+ _siteDomainMapper = siteDomainMapper;
+ _umbracoContextAccessor = umbracoContextAccessor;
+ _uriUtility = uriUtility;
+ _localizationService = localizationService;
+ _publishedContentCache = publishedContentCache;
+ _domainCache = domainCache;
+ _idKeyMap = idKeyMap;
+ _documentUrlService = documentUrlService;
+ _navigationQueryService = navigationQueryService;
- requestSettings.OnChange(x => _requestSettings = x);
+ requestSettings.OnChange(x => _requestSettings = x);
}
#region GetOtherUrls
@@ -95,7 +99,7 @@ public class NewDefaultUrlProvider : IUrlProvider
// n is null at root
while (domainUris == null && n != null)
{
- n = n.Parent; // move to parent node
+ n = n.Parent(_publishedContentCache, _navigationQueryService); // move to parent node
domainUris = n == null
? null
: DomainUtilities.DomainsForNode(_domainCache, _siteDomainMapper, n.Id, current);
diff --git a/src/Umbraco.Core/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs
index 28cd4323eb..afde85a13d 100644
--- a/src/Umbraco.Core/Routing/PublishedRouter.cs
+++ b/src/Umbraco.Core/Routing/PublishedRouter.cs
@@ -301,7 +301,7 @@ public class PublishedRouter : IPublishedRouter
}
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
- IDomainCache? domainsCache = umbracoContext.PublishedSnapshot.Domains;
+ IDomainCache? domainsCache = umbracoContext.Domains;
var domains = domainsCache?.GetAll(false).ToList();
// determines whether a domain corresponds to a published document, since some
@@ -311,7 +311,7 @@ public class PublishedRouter : IPublishedRouter
bool IsPublishedContentDomain(Domain domain)
{
// just get it from content cache - optimize there, not here
- IPublishedContent? domainDocument = umbracoContext.PublishedSnapshot.Content?.GetById(domain.ContentId);
+ IPublishedContent? domainDocument = umbracoContext.Content?.GetById(domain.ContentId);
// not published - at all
if (domainDocument == null)
diff --git a/src/Umbraco.Core/Routing/UrlProvider.cs b/src/Umbraco.Core/Routing/UrlProvider.cs
index 067c748da1..f40c240a73 100644
--- a/src/Umbraco.Core/Routing/UrlProvider.cs
+++ b/src/Umbraco.Core/Routing/UrlProvider.cs
@@ -1,6 +1,10 @@
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
@@ -21,20 +25,50 @@ namespace Umbraco.Cms.Core.Routing
/// The list of URL providers.
/// The list of media URL providers.
/// The current variation accessor.
- public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IOptions routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor)
+ /// The content cache.
+ /// The query service for the in-memory navigation structure.
+ public UrlProvider(
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IOptions routingSettings,
+ UrlProviderCollection urlProviders,
+ MediaUrlProviderCollection mediaUrlProviders,
+ IVariationContextAccessor variationContextAccessor,
+ IPublishedContentCache contentCache,
+ IDocumentNavigationQueryService navigationQueryService)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_urlProviders = urlProviders;
_mediaUrlProviders = mediaUrlProviders;
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
+ _contentCache = contentCache;
+ _navigationQueryService = navigationQueryService;
Mode = routingSettings.Value.UrlProviderMode;
+ }
+ [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
+ public UrlProvider(
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IOptions routingSettings,
+ UrlProviderCollection urlProviders,
+ MediaUrlProviderCollection mediaUrlProviders,
+ IVariationContextAccessor variationContextAccessor)
+ : this(
+ umbracoContextAccessor,
+ routingSettings,
+ urlProviders,
+ mediaUrlProviders,
+ variationContextAccessor,
+ StaticServiceProvider.Instance.GetRequiredService(),
+ StaticServiceProvider.Instance.GetRequiredService())
+ {
}
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IEnumerable _urlProviders;
private readonly IEnumerable _mediaUrlProviders;
private readonly IVariationContextAccessor _variationContextAccessor;
+ private readonly IPublishedContentCache _contentCache;
+ private readonly IDocumentNavigationQueryService _navigationQueryService;
///