diff --git a/.editorconfig b/.editorconfig
index eba04ad32676..faf5c7766a86 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -282,7 +282,7 @@ dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR___
# All public/protected/protected_internal constant fields must be PascalCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
-dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
+dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal, internal, private
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
@@ -356,24 +356,13 @@ dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning
-# Private static fields use camelCase and start with s_
-dotnet_naming_symbols.private_static_field_symbols.applicable_accessibilities = private
-dotnet_naming_symbols.private_static_field_symbols.required_modifiers = static, shared
-dotnet_naming_symbols.private_static_field_symbols.applicable_kinds = field
-dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.symbols = private_static_field_symbols
-dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.style = camel_case_and_prefix_with_s_underscore_style
-dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.severity = warning
-dotnet_naming_style.camel_case_and_prefix_with_s_underscore_style.required_prefix = s_
-dotnet_naming_style.camel_case_and_prefix_with_s_underscore_style.capitalization = camel_case
-
# Instance fields use camelCase and are prefixed with '_'
-dotnet_naming_symbols.private_field_symbols.applicable_accessibilities = private
-dotnet_naming_symbols.private_field_symbols.applicable_kinds = field
-dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.symbols = private_field_symbols
-dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.style = camel_case_and_prefix_with_underscore_style
-dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.severity = warning
-dotnet_naming_style.camel_case_and_prefix_with_underscore_style.required_prefix = _
-dotnet_naming_style.camel_case_and_prefix_with_underscore_style.capitalization = camel_case
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = warning
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+dotnet_naming_style.instance_field_style.required_prefix = _
##########################################
# License
@@ -408,4 +397,4 @@ dotnet_naming_style.camel_case_and_prefix_with_underscore_style.capitalization
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
-##########################################
\ No newline at end of file
+##########################################
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
index be6f013f263e..d357311dd5ed 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
@@ -180,8 +180,7 @@ public override string GetConcat(params string[] args)
return string.Join(" || ", args.AsEnumerable());
}
- public override string GetColumn(DatabaseType dbType, string tableName, string columnName, string columnAlias,
- string? referenceName = null, bool forInsert = false)
+ public override string GetColumn(DatabaseType dbType, string tableName, string columnName, string? columnAlias, string? referenceName = null, bool forInsert = false)
{
if (forInsert)
{
diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs
index fc59d0601676..4657c8a68ab1 100644
--- a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs
+++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs
@@ -8,54 +8,55 @@
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Infrastructure.Persistence;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+
+///
+/// Ensures that distributed cache events are setup and the is initialized
+///
+public sealed class DatabaseServerMessengerNotificationHandler :
+ INotificationHandler, INotificationHandler
{
+ private readonly IUmbracoDatabaseFactory _databaseFactory;
+ private readonly ILogger _logger;
+ private readonly IServerMessenger _messenger;
+ private readonly IRuntimeState _runtimeState;
+
///
- /// Ensures that distributed cache events are setup and the is initialized
+ /// Initializes a new instance of the class.
///
- public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler, INotificationHandler
+ public DatabaseServerMessengerNotificationHandler(
+ IServerMessenger serverMessenger,
+ IUmbracoDatabaseFactory databaseFactory,
+ ILogger logger,
+ IRuntimeState runtimeState)
+ {
+ _databaseFactory = databaseFactory;
+ _logger = logger;
+ _messenger = serverMessenger;
+ _runtimeState = runtimeState;
+ }
+
+ ///
+ public void Handle(UmbracoApplicationStartingNotification notification)
{
- private readonly IServerMessenger _messenger;
- private readonly IUmbracoDatabaseFactory _databaseFactory;
- private readonly ILogger _logger;
- private readonly IRuntimeState _runtimeState;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public DatabaseServerMessengerNotificationHandler(
- IServerMessenger serverMessenger,
- IUmbracoDatabaseFactory databaseFactory,
- ILogger logger,
- IRuntimeState runtimeState)
+ if (_runtimeState.Level != RuntimeLevel.Run)
{
- _databaseFactory = databaseFactory;
- _logger = logger;
- _messenger = serverMessenger;
- _runtimeState = runtimeState;
+ return;
}
- ///
- public void Handle(UmbracoApplicationStartingNotification notification)
+ if (_databaseFactory.CanConnect == false)
{
- if (_runtimeState.Level != RuntimeLevel.Run)
- {
- return;
- }
-
- if (_databaseFactory.CanConnect == false)
- {
- _logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server.");
- return;
- }
-
- // Sync on startup, this will run through the messenger's initialization sequence
- _messenger?.Sync();
+ _logger.LogWarning(
+ "Cannot connect to the database, distributed calls will not be enabled for this server.");
+ return;
}
- ///
- /// Clear the batch on end request
- ///
- public void Handle(UmbracoRequestEndNotification notification) => _messenger?.SendMessages();
+ // Sync on startup, this will run through the messenger's initialization sequence
+ _messenger?.Sync();
}
+
+ ///
+ /// Clear the batch on end request
+ ///
+ public void Handle(UmbracoRequestEndNotification notification) => _messenger?.SendMessages();
}
diff --git a/src/Umbraco.Infrastructure/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Infrastructure/Cache/DefaultRepositoryCachePolicy.cs
index b18cce9b3d55..7f7f8d678422 100644
--- a/src/Umbraco.Infrastructure/Cache/DefaultRepositoryCachePolicy.cs
+++ b/src/Umbraco.Infrastructure/Cache/DefaultRepositoryCachePolicy.cs
@@ -1,268 +1,273 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System;
-using System.Collections.Generic;
-using System.Linq;
using Umbraco.Cms.Core.Models.Entities;
-using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Infrastructure.Scoping;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+
+///
+/// Represents the default cache policy.
+///
+/// The type of the entity.
+/// The type of the identifier.
+///
+/// The default cache policy caches entities with a 5 minutes sliding expiration.
+/// Each entity is cached individually.
+/// If options.GetAllCacheAllowZeroCount then a 'zero-count' array is cached when GetAll finds nothing.
+/// If options.GetAllCacheValidateCount then we check against the db when getting many entities.
+///
+public class DefaultRepositoryCachePolicy : RepositoryCachePolicyBase
+ where TEntity : class, IEntity
{
- ///
- /// Represents the default cache policy.
- ///
- /// The type of the entity.
- /// The type of the identifier.
- ///
- /// The default cache policy caches entities with a 5 minutes sliding expiration.
- /// Each entity is cached individually.
- /// If options.GetAllCacheAllowZeroCount then a 'zero-count' array is cached when GetAll finds nothing.
- /// If options.GetAllCacheValidateCount then we check against the db when getting many entities.
- ///
- public class DefaultRepositoryCachePolicy : RepositoryCachePolicyBase
- where TEntity : class, IEntity
- {
- private static readonly TEntity[] s_emptyEntities = new TEntity[0]; // const
- private readonly RepositoryCachePolicyOptions _options;
+ private static readonly TEntity[] _emptyEntities = new TEntity[0]; // const
+ private readonly RepositoryCachePolicyOptions _options;
+
+ public DefaultRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options)
+ : base(cache, scopeAccessor) =>
+ _options = options ?? throw new ArgumentNullException(nameof(options));
- public DefaultRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options)
- : base(cache, scopeAccessor)
+ protected string EntityTypeCacheKey { get; } = $"uRepo_{typeof(TEntity).Name}_";
+
+ ///
+ public override void Create(TEntity entity, Action persistNew)
+ {
+ if (entity == null)
{
- _options = options ?? throw new ArgumentNullException(nameof(options));
+ throw new ArgumentNullException(nameof(entity));
}
- protected string GetEntityCacheKey(int id) => EntityTypeCacheKey + id;
-
- protected string GetEntityCacheKey(TId? id)
+ try
{
- if (EqualityComparer.Default.Equals(id, default))
- {
- return string.Empty;
- }
+ persistNew(entity);
- if (typeof(TId).IsValueType)
+ // just to be safe, we cannot cache an item without an identity
+ if (entity.HasIdentity)
{
- return EntityTypeCacheKey + id;
- }
- else
- {
- return EntityTypeCacheKey + id?.ToString()?.ToUpperInvariant();
+ Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
}
+
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.Clear(EntityTypeCacheKey);
}
+ catch
+ {
+ // if an exception is thrown we need to remove the entry from cache,
+ // this is ONLY a work around because of the way
+ // that we cache entities: http://issues.umbraco.org/issue/U4-4259
+ Cache.Clear(GetEntityCacheKey(entity.Id));
- protected string EntityTypeCacheKey { get; } = $"uRepo_{typeof(TEntity).Name}_";
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.Clear(EntityTypeCacheKey);
- protected virtual void InsertEntity(string cacheKey, TEntity entity)
- => Cache.Insert(cacheKey, () => entity, TimeSpan.FromMinutes(5), true);
+ throw;
+ }
+ }
- protected virtual void InsertEntities(TId[]? ids, TEntity[]? entities)
+ ///
+ public override void Update(TEntity entity, Action persistUpdated)
+ {
+ if (entity == null)
{
- if (ids?.Length == 0 && entities?.Length == 0 && _options.GetAllCacheAllowZeroCount)
- {
- // getting all of them, and finding nothing.
- // if we can cache a zero count, cache an empty array,
- // for as long as the cache is not cleared (no expiration)
- Cache.Insert(EntityTypeCacheKey, () => s_emptyEntities);
- }
- else
- {
- if (entities is not null)
- {
- // individually cache each item
- foreach (var entity in entities)
- {
- var capture = entity;
- Cache.Insert(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true);
- }
- }
- }
+ throw new ArgumentNullException(nameof(entity));
}
- ///
- public override void Create(TEntity entity, Action persistNew)
+ try
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
+ persistUpdated(entity);
- try
+ // just to be safe, we cannot cache an item without an identity
+ if (entity.HasIdentity)
{
- persistNew(entity);
-
- // just to be safe, we cannot cache an item without an identity
- if (entity.HasIdentity)
- {
- Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
- }
-
- // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(EntityTypeCacheKey);
+ Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
}
- catch
- {
- // if an exception is thrown we need to remove the entry from cache,
- // this is ONLY a work around because of the way
- // that we cache entities: http://issues.umbraco.org/issue/U4-4259
- Cache.Clear(GetEntityCacheKey(entity.Id));
-
- // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(EntityTypeCacheKey);
- throw;
- }
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.Clear(EntityTypeCacheKey);
}
-
- ///
- public override void Update(TEntity entity, Action persistUpdated)
+ catch
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
-
- try
- {
- persistUpdated(entity);
-
- // just to be safe, we cannot cache an item without an identity
- if (entity.HasIdentity)
- {
- Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
- }
-
- // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(EntityTypeCacheKey);
- }
- catch
- {
- // if an exception is thrown we need to remove the entry from cache,
- // this is ONLY a work around because of the way
- // that we cache entities: http://issues.umbraco.org/issue/U4-4259
- Cache.Clear(GetEntityCacheKey(entity.Id));
+ // if an exception is thrown we need to remove the entry from cache,
+ // this is ONLY a work around because of the way
+ // that we cache entities: http://issues.umbraco.org/issue/U4-4259
+ Cache.Clear(GetEntityCacheKey(entity.Id));
- // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(EntityTypeCacheKey);
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.Clear(EntityTypeCacheKey);
- throw;
- }
+ throw;
}
+ }
- ///
- public override void Delete(TEntity entity, Action persistDeleted)
+ ///
+ public override void Delete(TEntity entity, Action persistDeleted)
+ {
+ if (entity == null)
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
-
- try
- {
- persistDeleted(entity);
- }
- finally
- {
- // whatever happens, clear the cache
- var cacheKey = GetEntityCacheKey(entity.Id);
- Cache.Clear(cacheKey);
- // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(EntityTypeCacheKey);
- }
+ throw new ArgumentNullException(nameof(entity));
}
- ///
- public override TEntity? Get(TId? id, Func performGet, Func?> performGetAll)
+ try
{
- var cacheKey = GetEntityCacheKey(id);
- var fromCache = Cache.GetCacheItem(cacheKey);
-
- // if found in cache then return else fetch and cache
- if (fromCache != null)
- {
- return fromCache;
- }
-
- var entity = performGet(id);
-
- if (entity != null && entity.HasIdentity)
- {
- InsertEntity(cacheKey, entity);
- }
+ persistDeleted(entity);
+ }
+ finally
+ {
+ // whatever happens, clear the cache
+ var cacheKey = GetEntityCacheKey(entity.Id);
+ Cache.Clear(cacheKey);
- return entity;
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.Clear(EntityTypeCacheKey);
}
+ }
- ///
- public override TEntity? GetCached(TId id)
+ ///
+ public override TEntity? Get(TId? id, Func performGet, Func?> performGetAll)
+ {
+ var cacheKey = GetEntityCacheKey(id);
+ TEntity? fromCache = Cache.GetCacheItem(cacheKey);
+
+ // if found in cache then return else fetch and cache
+ if (fromCache != null)
{
- var cacheKey = GetEntityCacheKey(id);
- return Cache.GetCacheItem(cacheKey);
+ return fromCache;
}
- ///
- public override bool Exists(TId id, Func performExists, Func?> performGetAll)
+ TEntity? entity = performGet(id);
+
+ if (entity != null && entity.HasIdentity)
{
- // if found in cache the return else check
- var cacheKey = GetEntityCacheKey(id);
- var fromCache = Cache.GetCacheItem(cacheKey);
- return fromCache != null || performExists(id);
+ InsertEntity(cacheKey, entity);
}
- ///
- public override TEntity[] GetAll(TId[]? ids, Func?> performGetAll)
+ return entity;
+ }
+
+ ///
+ public override TEntity? GetCached(TId id)
+ {
+ var cacheKey = GetEntityCacheKey(id);
+ return Cache.GetCacheItem(cacheKey);
+ }
+
+ ///
+ public override bool Exists(TId id, Func performExists, Func?> performGetAll)
+ {
+ // if found in cache the return else check
+ var cacheKey = GetEntityCacheKey(id);
+ TEntity? fromCache = Cache.GetCacheItem(cacheKey);
+ return fromCache != null || performExists(id);
+ }
+
+ ///
+ public override TEntity[] GetAll(TId[]? ids, Func?> performGetAll)
+ {
+ if (ids?.Length > 0)
{
- if (ids?.Length > 0)
+ // try to get each entity from the cache
+ // if we can find all of them, return
+ TEntity[] entities = ids.Select(GetCached).WhereNotNull().ToArray();
+ if (ids.Length.Equals(entities.Length))
{
- // try to get each entity from the cache
- // if we can find all of them, return
- var entities = ids.Select(GetCached).WhereNotNull().ToArray();
- if (ids.Length.Equals(entities.Length))
- return entities; // no need for null checks, we are not caching nulls
+ return entities; // no need for null checks, we are not caching nulls
}
- else
- {
- // get everything we have
- var entities = Cache.GetCacheItemsByKeySearch(EntityTypeCacheKey)?
- .ToArray(); // no need for null checks, we are not caching nulls
+ }
+ else
+ {
+ // get everything we have
+ TEntity?[] entities = Cache.GetCacheItemsByKeySearch(EntityTypeCacheKey)
+ .ToArray(); // no need for null checks, we are not caching nulls
- if (entities?.Length > 0)
+ if (entities.Length > 0)
+ {
+ // if some of them were in the cache...
+ if (_options.GetAllCacheValidateCount)
{
- // if some of them were in the cache...
- if (_options.GetAllCacheValidateCount)
+ // need to validate the count, get the actual count and return if ok
+ if (_options.PerformCount is not null)
{
- // need to validate the count, get the actual count and return if ok
- if (_options.PerformCount is not null)
+ var totalCount = _options.PerformCount();
+ if (entities.Length == totalCount)
{
- var totalCount = _options.PerformCount();
- if (entities.Length == totalCount)
- return entities.WhereNotNull().ToArray();
+ return entities.WhereNotNull().ToArray();
}
}
- else
- {
- // no need to validate, just return what we have and assume it's all there is
- return entities.WhereNotNull().ToArray();
- }
}
- else if (_options.GetAllCacheAllowZeroCount)
+ else
{
- // if none of them were in the cache
- // and we allow zero count - check for the special (empty) entry
- var empty = Cache.GetCacheItem(EntityTypeCacheKey);
- if (empty != null) return empty;
+ // no need to validate, just return what we have and assume it's all there is
+ return entities.WhereNotNull().ToArray();
}
}
+ else if (_options.GetAllCacheAllowZeroCount)
+ {
+ // if none of them were in the cache
+ // and we allow zero count - check for the special (empty) entry
+ TEntity[]? empty = Cache.GetCacheItem(EntityTypeCacheKey);
+ if (empty != null)
+ {
+ return empty;
+ }
+ }
+ }
+
+ // cache failed, get from repo and cache
+ TEntity[]? repoEntities = performGetAll(ids)?
+ .WhereNotNull() // exclude nulls!
+ .Where(x => x.HasIdentity) // be safe, though would be weird...
+ .ToArray();
- // cache failed, get from repo and cache
- var repoEntities = performGetAll(ids)?
- .WhereNotNull() // exclude nulls!
- .Where(x => x.HasIdentity) // be safe, though would be weird...
- .ToArray();
+ // note: if empty & allow zero count, will cache a special (empty) entry
+ InsertEntities(ids, repoEntities);
- // note: if empty & allow zero count, will cache a special (empty) entry
- InsertEntities(ids, repoEntities);
+ return repoEntities ?? Array.Empty();
+ }
+
+ ///
+ public override void ClearAll() => Cache.ClearByKey(EntityTypeCacheKey);
+
+ protected string GetEntityCacheKey(int id) => EntityTypeCacheKey + id;
+
+ protected string GetEntityCacheKey(TId? id)
+ {
+ if (EqualityComparer.Default.Equals(id, default))
+ {
+ return string.Empty;
+ }
- return repoEntities ?? Array.Empty();
+ if (typeof(TId).IsValueType)
+ {
+ return EntityTypeCacheKey + id;
}
- ///
- public override void ClearAll()
+ return EntityTypeCacheKey + id?.ToString()?.ToUpperInvariant();
+ }
+
+ protected virtual void InsertEntity(string cacheKey, TEntity entity)
+ => Cache.Insert(cacheKey, () => entity, TimeSpan.FromMinutes(5), true);
+
+ protected virtual void InsertEntities(TId[]? ids, TEntity[]? entities)
+ {
+ if (ids?.Length == 0 && entities?.Length == 0 && _options.GetAllCacheAllowZeroCount)
{
- Cache.ClearByKey(EntityTypeCacheKey);
+ // getting all of them, and finding nothing.
+ // if we can cache a zero count, cache an empty array,
+ // for as long as the cache is not cleared (no expiration)
+ Cache.Insert(EntityTypeCacheKey, () => _emptyEntities);
+ }
+ else
+ {
+ if (entities is not null)
+ {
+ // individually cache each item
+ foreach (TEntity entity in entities)
+ {
+ TEntity capture = entity;
+ Cache.Insert(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true);
+ }
+ }
}
}
}
diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs
index 6e6f549b034d..11119aaf66f4 100644
--- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs
+++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs
@@ -1,365 +1,341 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System.Linq;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Notifications;
-using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+public class DistributedCacheBinder :
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler
{
+ private readonly DistributedCache _distributedCache;
+
///
- /// Default implementation.
+ /// Initializes a new instance of the class.
///
- public class DistributedCacheBinder :
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler,
- INotificationHandler
+ public DistributedCacheBinder(DistributedCache distributedCache)
{
- private readonly DistributedCache _distributedCache;
+ _distributedCache = distributedCache;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- public DistributedCacheBinder(DistributedCache distributedCache)
- {
- _distributedCache = distributedCache;
- }
+ #region PublicAccessService
- #region PublicAccessService
+ public void Handle(PublicAccessEntrySavedNotification notification)
+ {
+ _distributedCache.RefreshPublicAccess();
+ }
- public void Handle(PublicAccessEntrySavedNotification notification)
- {
- _distributedCache.RefreshPublicAccess();
- }
+ public void Handle(PublicAccessEntryDeletedNotification notification) => _distributedCache.RefreshPublicAccess();
- public void Handle(PublicAccessEntryDeletedNotification notification)
- {
- _distributedCache.RefreshPublicAccess();
+ #endregion
- }
+ #region ContentService
+
+ public void Handle(ContentTreeChangeNotification notification)
+ {
+ _distributedCache.RefreshContentCache(notification.Changes.ToArray());
+ }
- #endregion
+ // private void ContentService_SavedBlueprint(IContentService sender, SaveEventArgs e)
+ // {
+ // _distributedCache.RefreshUnpublishedPageCache(e.SavedEntities.ToArray());
+ // }
- #region ContentService
+ // private void ContentService_DeletedBlueprint(IContentService sender, DeleteEventArgs e)
+ // {
+ // _distributedCache.RemoveUnpublishedPageCache(e.DeletedEntities.ToArray());
+ // }
+ #endregion
- ///
- /// Handles cache refreshing for when content is copied
- ///
- ///
- ///
- ///
- /// When an entity is copied new permissions may be assigned to it based on it's parent, if that is the
- /// case then we need to clear all user permissions cache.
- ///
- private void ContentService_Copied(IContentService sender, CopyEventArgs e)
+ #region LocalizationService / Dictionary
+ public void Handle(DictionaryItemSavedNotification notification)
+ {
+ foreach (IDictionaryItem entity in notification.SavedEntities)
{
+ _distributedCache.RefreshDictionaryCache(entity.Id);
}
+ }
-
- public void Handle(ContentTreeChangeNotification notification)
+ public void Handle(DictionaryItemDeletedNotification notification)
+ {
+ foreach (IDictionaryItem entity in notification.DeletedEntities)
{
- _distributedCache.RefreshContentCache(notification.Changes.ToArray());
+ _distributedCache.RemoveDictionaryCache(entity.Id);
}
+ }
- //private void ContentService_SavedBlueprint(IContentService sender, SaveEventArgs e)
- //{
- // _distributedCache.RefreshUnpublishedPageCache(e.SavedEntities.ToArray());
- //}
-
- //private void ContentService_DeletedBlueprint(IContentService sender, DeleteEventArgs e)
- //{
- // _distributedCache.RemoveUnpublishedPageCache(e.DeletedEntities.ToArray());
- //}
-
- #endregion
+ #endregion
- #region LocalizationService / Dictionary
- public void Handle(DictionaryItemSavedNotification notification)
- {
- foreach (IDictionaryItem entity in notification.SavedEntities)
- {
- _distributedCache.RefreshDictionaryCache(entity.Id);
- }
- }
+ #region DataTypeService
- public void Handle(DictionaryItemDeletedNotification notification)
+ public void Handle(DataTypeSavedNotification notification)
+ {
+ foreach (IDataType entity in notification.SavedEntities)
{
- foreach (IDictionaryItem entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveDictionaryCache(entity.Id);
- }
+ _distributedCache.RefreshDataTypeCache(entity);
}
- #endregion
-
- #region DataTypeService
+ _distributedCache.RefreshValueEditorCache(notification.SavedEntities);
+ }
- public void Handle(DataTypeSavedNotification notification)
+ public void Handle(DataTypeDeletedNotification notification)
+ {
+ foreach (IDataType entity in notification.DeletedEntities)
{
- foreach (IDataType entity in notification.SavedEntities)
- {
- _distributedCache.RefreshDataTypeCache(entity);
- }
- _distributedCache.RefreshValueEditorCache(notification.SavedEntities);
+ _distributedCache.RemoveDataTypeCache(entity);
}
- public void Handle(DataTypeDeletedNotification notification)
- {
- foreach (IDataType entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveDataTypeCache(entity);
- }
- _distributedCache.RefreshValueEditorCache(notification.DeletedEntities);
- }
+ _distributedCache.RefreshValueEditorCache(notification.DeletedEntities);
+ }
- #endregion
+ #endregion
- #region DomainService
+ #region DomainService
- public void Handle(DomainSavedNotification notification)
+ public void Handle(DomainSavedNotification notification)
+ {
+ foreach (IDomain entity in notification.SavedEntities)
{
- foreach (IDomain entity in notification.SavedEntities)
- {
- _distributedCache.RefreshDomainCache(entity);
- }
+ _distributedCache.RefreshDomainCache(entity);
}
+ }
- public void Handle(DomainDeletedNotification notification)
+ public void Handle(DomainDeletedNotification notification)
+ {
+ foreach (IDomain entity in notification.DeletedEntities)
{
- foreach (IDomain entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveDomainCache(entity);
- }
+ _distributedCache.RemoveDomainCache(entity);
}
+ }
- #endregion
+ #endregion
- #region LocalizationService / Language
+ #region LocalizationService / Language
- ///
- /// Fires when a language is deleted
- ///
- ///
- public void Handle(LanguageDeletedNotification notification)
+ ///
+ /// Fires when a language is deleted
+ ///
+ ///
+ public void Handle(LanguageDeletedNotification notification)
+ {
+ foreach (ILanguage entity in notification.DeletedEntities)
{
- foreach (ILanguage entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveLanguageCache(entity);
- }
+ _distributedCache.RemoveLanguageCache(entity);
}
+ }
- ///
- /// Fires when a language is saved
- ///
- ///
- public void Handle(LanguageSavedNotification notification)
+ ///
+ /// Fires when a language is saved
+ ///
+ ///
+ public void Handle(LanguageSavedNotification notification)
+ {
+ foreach (ILanguage entity in notification.SavedEntities)
{
- foreach (ILanguage entity in notification.SavedEntities)
- {
- _distributedCache.RefreshLanguageCache(entity);
- }
+ _distributedCache.RefreshLanguageCache(entity);
}
+ }
- #endregion
+ #endregion
- #region Content|Media|MemberTypeService
+ #region Content|Media|MemberTypeService
- public void Handle(ContentTypeChangedNotification notification) =>
- _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
+ public void Handle(ContentTypeChangedNotification notification) =>
+ _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
- public void Handle(MediaTypeChangedNotification notification) =>
- _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
+ public void Handle(MediaTypeChangedNotification notification) =>
+ _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
- public void Handle(MemberTypeChangedNotification notification) =>
- _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
+ public void Handle(MemberTypeChangedNotification notification) =>
+ _distributedCache.RefreshContentTypeCache(notification.Changes.ToArray());
- #endregion
+ #endregion
- #region UserService
+ #region UserService
- public void Handle(UserSavedNotification notification)
+ public void Handle(UserSavedNotification notification)
+ {
+ foreach (IUser entity in notification.SavedEntities)
{
- foreach (IUser entity in notification.SavedEntities)
- {
- _distributedCache.RefreshUserCache(entity.Id);
- }
+ _distributedCache.RefreshUserCache(entity.Id);
}
+ }
- public void Handle(UserDeletedNotification notification)
+ public void Handle(UserDeletedNotification notification)
+ {
+ foreach (IUser entity in notification.DeletedEntities)
{
- foreach (IUser entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveUserCache(entity.Id);
- }
+ _distributedCache.RemoveUserCache(entity.Id);
}
+ }
- public void Handle(UserGroupWithUsersSavedNotification notification)
+ public void Handle(UserGroupWithUsersSavedNotification notification)
+ {
+ foreach (UserGroupWithUsers entity in notification.SavedEntities)
{
- foreach (UserGroupWithUsers entity in notification.SavedEntities)
- {
- _distributedCache.RefreshUserGroupCache(entity.UserGroup.Id);
- }
+ _distributedCache.RefreshUserGroupCache(entity.UserGroup.Id);
}
+ }
- public void Handle(UserGroupDeletedNotification notification)
+ public void Handle(UserGroupDeletedNotification notification)
+ {
+ foreach (IUserGroup entity in notification.DeletedEntities)
{
- foreach (IUserGroup entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveUserGroupCache(entity.Id);
- }
+ _distributedCache.RemoveUserGroupCache(entity.Id);
}
+ }
- #endregion
+ #endregion
- #region FileService
+ #region FileService
- ///
- /// Removes cache for template
- ///
- ///
- public void Handle(TemplateDeletedNotification notification)
+ ///
+ /// Removes cache for template
+ ///
+ ///
+ public void Handle(TemplateDeletedNotification notification)
+ {
+ foreach (ITemplate entity in notification.DeletedEntities)
{
- foreach (ITemplate entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveTemplateCache(entity.Id);
- }
+ _distributedCache.RemoveTemplateCache(entity.Id);
}
+ }
- ///
- /// Refresh cache for template
- ///
- ///
- public void Handle(TemplateSavedNotification notification)
+ ///
+ /// Refresh cache for template
+ ///
+ ///
+ public void Handle(TemplateSavedNotification notification)
+ {
+ foreach (ITemplate entity in notification.SavedEntities)
{
- foreach (ITemplate entity in notification.SavedEntities)
- {
- _distributedCache.RefreshTemplateCache(entity.Id);
- }
+ _distributedCache.RefreshTemplateCache(entity.Id);
}
+ }
- #endregion
+ #endregion
- #region MacroService
+ #region MacroService
- public void Handle(MacroDeletedNotification notification)
+ public void Handle(MacroDeletedNotification notification)
+ {
+ foreach (IMacro entity in notification.DeletedEntities)
{
- foreach (IMacro entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveMacroCache(entity);
- }
+ _distributedCache.RemoveMacroCache(entity);
}
+ }
- public void Handle(MacroSavedNotification notification)
+ public void Handle(MacroSavedNotification notification)
+ {
+ foreach (IMacro entity in notification.SavedEntities)
{
- foreach (IMacro entity in notification.SavedEntities)
- {
- _distributedCache.RefreshMacroCache(entity);
- }
+ _distributedCache.RefreshMacroCache(entity);
}
+ }
- #endregion
+ #endregion
- #region MediaService
+ #region MediaService
- public void Handle(MediaTreeChangeNotification notification)
- {
- _distributedCache.RefreshMediaCache(notification.Changes.ToArray());
- }
+ public void Handle(MediaTreeChangeNotification notification)
+ {
+ _distributedCache.RefreshMediaCache(notification.Changes.ToArray());
+ }
- #endregion
+ #endregion
- #region MemberService
+ #region MemberService
- public void Handle(MemberDeletedNotification notification)
- {
- _distributedCache.RemoveMemberCache(notification.DeletedEntities.ToArray());
- }
+ public void Handle(MemberDeletedNotification notification)
+ {
+ _distributedCache.RemoveMemberCache(notification.DeletedEntities.ToArray());
+ }
- public void Handle(MemberSavedNotification notification)
- {
- _distributedCache.RefreshMemberCache(notification.SavedEntities.ToArray());
- }
+ public void Handle(MemberSavedNotification notification)
+ {
+ _distributedCache.RefreshMemberCache(notification.SavedEntities.ToArray());
+ }
- #endregion
+ #endregion
- #region MemberGroupService
+ #region MemberGroupService
- ///
- /// Fires when a member group is deleted
- ///
- ///
- public void Handle(MemberGroupDeletedNotification notification)
+ ///
+ /// Fires when a member group is deleted
+ ///
+ ///
+ public void Handle(MemberGroupDeletedNotification notification)
+ {
+ foreach (IMemberGroup entity in notification.DeletedEntities)
{
- foreach (IMemberGroup entity in notification.DeletedEntities)
- {
- _distributedCache.RemoveMemberGroupCache(entity.Id);
- }
+ _distributedCache.RemoveMemberGroupCache(entity.Id);
}
+ }
- ///
- /// Fires when a member group is saved
- ///
- ///
- public void Handle(MemberGroupSavedNotification notification)
+ ///
+ /// Fires when a member group is saved
+ ///
+ ///
+ public void Handle(MemberGroupSavedNotification notification)
+ {
+ foreach (IMemberGroup entity in notification.SavedEntities)
{
- foreach (IMemberGroup entity in notification.SavedEntities)
- {
- _distributedCache.RemoveMemberGroupCache(entity.Id);
- }
+ _distributedCache.RemoveMemberGroupCache(entity.Id);
}
+ }
- #endregion
+ #endregion
- #region RelationType
+ #region RelationType
- public void Handle(RelationTypeSavedNotification notification)
+ public void Handle(RelationTypeSavedNotification notification)
+ {
+ DistributedCache dc = _distributedCache;
+ foreach (IRelationType entity in notification.SavedEntities)
{
- DistributedCache dc = _distributedCache;
- foreach (IRelationType entity in notification.SavedEntities)
- {
- dc.RefreshRelationTypeCache(entity.Id);
- }
+ dc.RefreshRelationTypeCache(entity.Id);
}
+ }
- public void Handle(RelationTypeDeletedNotification notification)
+ public void Handle(RelationTypeDeletedNotification notification)
+ {
+ DistributedCache dc = _distributedCache;
+ foreach (IRelationType entity in notification.DeletedEntities)
{
- DistributedCache dc = _distributedCache;
- foreach (IRelationType entity in notification.DeletedEntities)
- {
- dc.RemoveRelationTypeCache(entity.Id);
- }
+ dc.RemoveRelationTypeCache(entity.Id);
}
-
- #endregion
}
+
+ #endregion
}
diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs
index ceac767a8cec..dfa7d9b605a3 100644
--- a/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs
+++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs
@@ -1,327 +1,376 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System.Collections.Generic;
-using System.Linq;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.Changes;
-namespace Umbraco.Extensions
+namespace Umbraco.Extensions;
+
+///
+/// Extension methods for .
+///
+public static class DistributedCacheExtensions
{
- ///
- /// Extension methods for .
- ///
- public static class DistributedCacheExtensions
- {
- #region PublicAccessCache
+ #region PublicAccessCache
- public static void RefreshPublicAccess(this DistributedCache dc)
- {
- dc.RefreshAll(PublicAccessCacheRefresher.UniqueId);
- }
+ public static void RefreshPublicAccess(this DistributedCache dc)
+ {
+ dc.RefreshAll(PublicAccessCacheRefresher.UniqueId);
+ }
- #endregion
+ #endregion
- #region User cache
+ #region User cache
- public static void RemoveUserCache(this DistributedCache dc, int userId)
- {
- dc.Remove(UserCacheRefresher.UniqueId, userId);
- }
+ public static void RemoveUserCache(this DistributedCache dc, int userId)
+ {
+ dc.Remove(UserCacheRefresher.UniqueId, userId);
+ }
- public static void RefreshUserCache(this DistributedCache dc, int userId)
- {
- dc.Refresh(UserCacheRefresher.UniqueId, userId);
- }
+ public static void RefreshUserCache(this DistributedCache dc, int userId)
+ {
+ dc.Refresh(UserCacheRefresher.UniqueId, userId);
+ }
- public static void RefreshAllUserCache(this DistributedCache dc)
- {
- dc.RefreshAll(UserCacheRefresher.UniqueId);
- }
+ public static void RefreshAllUserCache(this DistributedCache dc)
+ {
+ dc.RefreshAll(UserCacheRefresher.UniqueId);
+ }
- #endregion
+ #endregion
- #region User group cache
+ #region User group cache
- public static void RemoveUserGroupCache(this DistributedCache dc, int userId)
- {
- dc.Remove(UserGroupCacheRefresher.UniqueId, userId);
- }
+ public static void RemoveUserGroupCache(this DistributedCache dc, int userId)
+ {
+ dc.Remove(UserGroupCacheRefresher.UniqueId, userId);
+ }
- public static void RefreshUserGroupCache(this DistributedCache dc, int userId)
- {
- dc.Refresh(UserGroupCacheRefresher.UniqueId, userId);
- }
+ public static void RefreshUserGroupCache(this DistributedCache dc, int userId)
+ {
+ dc.Refresh(UserGroupCacheRefresher.UniqueId, userId);
+ }
- public static void RefreshAllUserGroupCache(this DistributedCache dc)
- {
- dc.RefreshAll(UserGroupCacheRefresher.UniqueId);
- }
+ public static void RefreshAllUserGroupCache(this DistributedCache dc)
+ {
+ dc.RefreshAll(UserGroupCacheRefresher.UniqueId);
+ }
- #endregion
+ #endregion
- #region TemplateCache
+ #region TemplateCache
- public static void RefreshTemplateCache(this DistributedCache dc, int templateId)
- {
- dc.Refresh(TemplateCacheRefresher.UniqueId, templateId);
- }
+ public static void RefreshTemplateCache(this DistributedCache dc, int templateId)
+ {
+ dc.Refresh(TemplateCacheRefresher.UniqueId, templateId);
+ }
- public static void RemoveTemplateCache(this DistributedCache dc, int templateId)
- {
- dc.Remove(TemplateCacheRefresher.UniqueId, templateId);
- }
+ public static void RemoveTemplateCache(this DistributedCache dc, int templateId)
+ {
+ dc.Remove(TemplateCacheRefresher.UniqueId, templateId);
+ }
- #endregion
+ #endregion
- #region DictionaryCache
+ #region DictionaryCache
- public static void RefreshDictionaryCache(this DistributedCache dc, int dictionaryItemId)
- {
- dc.Refresh(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
- }
+ public static void RefreshDictionaryCache(this DistributedCache dc, int dictionaryItemId)
+ {
+ dc.Refresh(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
+ }
- public static void RemoveDictionaryCache(this DistributedCache dc, int dictionaryItemId)
- {
- dc.Remove(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
- }
+ public static void RemoveDictionaryCache(this DistributedCache dc, int dictionaryItemId)
+ {
+ dc.Remove(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
+ }
- #endregion
+ #endregion
- #region DataTypeCache
+ #region DataTypeCache
- public static void RefreshDataTypeCache(this DistributedCache dc, IDataType dataType)
+ public static void RefreshDataTypeCache(this DistributedCache dc, IDataType dataType)
+ {
+ if (dataType == null)
{
- if (dataType == null) return;
- var payloads = new[] { new DataTypeCacheRefresher.JsonPayload(dataType.Id, dataType.Key, false) };
- dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, payloads);
+ return;
}
- public static void RemoveDataTypeCache(this DistributedCache dc, IDataType dataType)
+ DataTypeCacheRefresher.JsonPayload[] payloads = new[] { new DataTypeCacheRefresher.JsonPayload(dataType.Id, dataType.Key, false) };
+ dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, payloads);
+ }
+
+ public static void RemoveDataTypeCache(this DistributedCache dc, IDataType dataType)
+ {
+ if (dataType == null)
{
- if (dataType == null) return;
- var payloads = new[] { new DataTypeCacheRefresher.JsonPayload(dataType.Id, dataType.Key, true) };
- dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, payloads);
+ return;
}
- #endregion
+ DataTypeCacheRefresher.JsonPayload[] payloads = new[] { new DataTypeCacheRefresher.JsonPayload(dataType.Id, dataType.Key, true) };
+ dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, payloads);
+ }
- #region ValueEditorCache
+ #endregion
- public static void RefreshValueEditorCache(this DistributedCache dc, IEnumerable dataTypes)
- {
- if (dataTypes is null)
- {
- return;
- }
+ #region ValueEditorCache
- var payloads = dataTypes.Select(x => new DataTypeCacheRefresher.JsonPayload(x.Id, x.Key, false));
- dc.RefreshByPayload(ValueEditorCacheRefresher.UniqueId, payloads);
+ public static void RefreshValueEditorCache(this DistributedCache dc, IEnumerable dataTypes)
+ {
+ if (dataTypes is null)
+ {
+ return;
}
- #endregion
+ IEnumerable payloads = dataTypes.Select(x => new DataTypeCacheRefresher.JsonPayload(x.Id, x.Key, false));
+ dc.RefreshByPayload(ValueEditorCacheRefresher.UniqueId, payloads);
+ }
- #region ContentCache
+ #endregion
- public static void RefreshAllContentCache(this DistributedCache dc)
- {
- var payloads = new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
+ #region ContentCache
- // note: refresh all content cache does refresh content types too
- dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
- }
+ public static void RefreshAllContentCache(this DistributedCache dc)
+ {
+ ContentCacheRefresher.JsonPayload[] payloads = new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
- public static void RefreshContentCache(this DistributedCache dc, TreeChange[] changes)
+ // note: refresh all content cache does refresh content types too
+ dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
+ }
+
+ public static void RefreshContentCache(this DistributedCache dc, TreeChange[] changes)
+ {
+ if (changes.Length == 0)
{
- if (changes.Length == 0) return;
+ return;
+ }
- var payloads = changes
- .Select(x => new ContentCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes));
+ IEnumerable payloads = changes
+ .Select(x => new ContentCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes));
- dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
- }
+ dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
+ }
- #endregion
+ #endregion
- #region MemberCache
+ #region MemberCache
- public static void RefreshMemberCache(this DistributedCache dc, params IMember[] members)
+ public static void RefreshMemberCache(this DistributedCache dc, params IMember[] members)
+ {
+ if (members.Length == 0)
{
- if (members.Length == 0) return;
- dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, false)));
+ return;
}
- public static void RemoveMemberCache(this DistributedCache dc, params IMember[] members)
+ dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, false)));
+ }
+
+ public static void RemoveMemberCache(this DistributedCache dc, params IMember[] members)
+ {
+ if (members.Length == 0)
{
- if (members.Length == 0) return;
- dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, true)));
+ return;
}
- #endregion
+ dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, true)));
+ }
- #region MemberGroupCache
+ #endregion
- public static void RefreshMemberGroupCache(this DistributedCache dc, int memberGroupId)
- {
- dc.Refresh(MemberGroupCacheRefresher.UniqueId, memberGroupId);
- }
+ #region MemberGroupCache
- public static void RemoveMemberGroupCache(this DistributedCache dc, int memberGroupId)
- {
- dc.Remove(MemberGroupCacheRefresher.UniqueId, memberGroupId);
- }
+ public static void RefreshMemberGroupCache(this DistributedCache dc, int memberGroupId)
+ {
+ dc.Refresh(MemberGroupCacheRefresher.UniqueId, memberGroupId);
+ }
- #endregion
+ public static void RemoveMemberGroupCache(this DistributedCache dc, int memberGroupId)
+ {
+ dc.Remove(MemberGroupCacheRefresher.UniqueId, memberGroupId);
+ }
- #region MediaCache
+ #endregion
- public static void RefreshAllMediaCache(this DistributedCache dc)
- {
- var payloads = new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
+ #region MediaCache
- // note: refresh all media cache does refresh content types too
- dc.RefreshByPayload(MediaCacheRefresher.UniqueId, payloads);
- }
+ public static void RefreshAllMediaCache(this DistributedCache dc)
+ {
+ MediaCacheRefresher.JsonPayload[] payloads = new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
+
+ // note: refresh all media cache does refresh content types too
+ dc.RefreshByPayload(MediaCacheRefresher.UniqueId, payloads);
+ }
- public static void RefreshMediaCache(this DistributedCache dc, TreeChange[] changes)
+ public static void RefreshMediaCache(this DistributedCache dc, TreeChange[] changes)
+ {
+ if (changes.Length == 0)
{
- if (changes.Length == 0) return;
+ return;
+ }
- var payloads = changes
- .Select(x => new MediaCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes));
+ IEnumerable payloads = changes
+ .Select(x => new MediaCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes));
- dc.RefreshByPayload(MediaCacheRefresher.UniqueId, payloads);
- }
+ dc.RefreshByPayload(MediaCacheRefresher.UniqueId, payloads);
+ }
- #endregion
+ #endregion
- #region Published Snapshot
+ #region Published Snapshot
- public static void RefreshAllPublishedSnapshot(this DistributedCache dc)
- {
- // note: refresh all content & media caches does refresh content types too
- dc.RefreshAllContentCache();
- dc.RefreshAllMediaCache();
- dc.RefreshAllDomainCache();
- }
+ public static void RefreshAllPublishedSnapshot(this DistributedCache dc)
+ {
+ // note: refresh all content & media caches does refresh content types too
+ dc.RefreshAllContentCache();
+ dc.RefreshAllMediaCache();
+ dc.RefreshAllDomainCache();
+ }
- #endregion
+ #endregion
- #region MacroCache
+ #region MacroCache
- public static void RefreshMacroCache(this DistributedCache dc, IMacro macro)
+ public static void RefreshMacroCache(this DistributedCache dc, IMacro macro)
+ {
+ if (macro == null)
{
- if (macro == null) return;
- var payloads = new[] { new MacroCacheRefresher.JsonPayload(macro.Id, macro.Alias) };
- dc.RefreshByPayload(MacroCacheRefresher.UniqueId, payloads);
+ return;
}
- public static void RemoveMacroCache(this DistributedCache dc, IMacro macro)
+ MacroCacheRefresher.JsonPayload[] payloads = new[] { new MacroCacheRefresher.JsonPayload(macro.Id, macro.Alias) };
+ dc.RefreshByPayload(MacroCacheRefresher.UniqueId, payloads);
+ }
+
+ public static void RemoveMacroCache(this DistributedCache dc, IMacro macro)
+ {
+ if (macro == null)
{
- if (macro == null) return;
- var payloads = new[] { new MacroCacheRefresher.JsonPayload(macro.Id, macro.Alias) };
- dc.RefreshByPayload(MacroCacheRefresher.UniqueId, payloads);
+ return;
}
- #endregion
+ MacroCacheRefresher.JsonPayload[] payloads = new[] { new MacroCacheRefresher.JsonPayload(macro.Id, macro.Alias) };
+ dc.RefreshByPayload(MacroCacheRefresher.UniqueId, payloads);
+ }
+
+ #endregion
- #region Content/Media/Member type cache
+ #region Content/Media/Member type cache
- public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ {
+ if (changes.Length == 0)
{
- if (changes.Length == 0) return;
+ return;
+ }
- var payloads = changes
- .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof (IContentType).Name, x.Item.Id, x.ChangeTypes));
+ IEnumerable payloads = changes
+ .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IContentType).Name, x.Item.Id, x.ChangeTypes));
- dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
- }
+ dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
+ }
- public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ {
+ if (changes.Length == 0)
{
- if (changes.Length == 0) return;
+ return;
+ }
- var payloads = changes
- .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMediaType).Name, x.Item.Id, x.ChangeTypes));
+ IEnumerable payloads = changes
+ .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMediaType).Name, x.Item.Id, x.ChangeTypes));
- dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
- }
+ dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
+ }
- public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ public static void RefreshContentTypeCache(this DistributedCache dc, ContentTypeChange[] changes)
+ {
+ if (changes.Length == 0)
{
- if (changes.Length == 0) return;
+ return;
+ }
- var payloads = changes
- .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMemberType).Name, x.Item.Id, x.ChangeTypes));
+ IEnumerable payloads = changes
+ .Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMemberType).Name, x.Item.Id, x.ChangeTypes));
- dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
- }
+ dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, payloads);
+ }
- #endregion
+ #endregion
- #region Domain Cache
+ #region Domain Cache
- public static void RefreshDomainCache(this DistributedCache dc, IDomain domain)
+ public static void RefreshDomainCache(this DistributedCache dc, IDomain domain)
+ {
+ if (domain == null)
{
- if (domain == null) return;
- var payloads = new[] { new DomainCacheRefresher.JsonPayload(domain.Id, DomainChangeTypes.Refresh) };
- dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
+ return;
}
- public static void RemoveDomainCache(this DistributedCache dc, IDomain domain)
- {
- if (domain == null) return;
- var payloads = new[] { new DomainCacheRefresher.JsonPayload(domain.Id, DomainChangeTypes.Remove) };
- dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
- }
+ DomainCacheRefresher.JsonPayload[] payloads = new[] { new DomainCacheRefresher.JsonPayload(domain.Id, DomainChangeTypes.Refresh) };
+ dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
+ }
- public static void RefreshAllDomainCache(this DistributedCache dc)
+ public static void RemoveDomainCache(this DistributedCache dc, IDomain domain)
+ {
+ if (domain == null)
{
- var payloads = new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) };
- dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
+ return;
}
- #endregion
-
- #region Language Cache
+ DomainCacheRefresher.JsonPayload[] payloads = new[] { new DomainCacheRefresher.JsonPayload(domain.Id, DomainChangeTypes.Remove) };
+ dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
+ }
- public static void RefreshLanguageCache(this DistributedCache dc, ILanguage language)
- {
- if (language == null) return;
+ public static void RefreshAllDomainCache(this DistributedCache dc)
+ {
+ DomainCacheRefresher.JsonPayload[] payloads = new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) };
+ dc.RefreshByPayload(DomainCacheRefresher.UniqueId, payloads);
+ }
- var payload = new LanguageCacheRefresher.JsonPayload(language.Id, language.IsoCode,
- language.WasPropertyDirty(nameof(ILanguage.IsoCode))
- ? LanguageCacheRefresher.JsonPayload.LanguageChangeType.ChangeCulture
- : LanguageCacheRefresher.JsonPayload.LanguageChangeType.Update);
+ #endregion
- dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
- }
+ #region Language Cache
- public static void RemoveLanguageCache(this DistributedCache dc, ILanguage language)
+ public static void RefreshLanguageCache(this DistributedCache dc, ILanguage language)
+ {
+ if (language == null)
{
- if (language == null) return;
-
- var payload = new LanguageCacheRefresher.JsonPayload(language.Id, language.IsoCode, LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove);
- dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
+ return;
}
- #endregion
+ var payload = new LanguageCacheRefresher.JsonPayload(
+ language.Id,
+ language.IsoCode,
+ language.WasPropertyDirty(nameof(ILanguage.IsoCode)) ? LanguageCacheRefresher.JsonPayload.LanguageChangeType.ChangeCulture : LanguageCacheRefresher.JsonPayload.LanguageChangeType.Update);
- #region Relation type cache
+ dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
+ }
- public static void RefreshRelationTypeCache(this DistributedCache dc, int id)
+ public static void RemoveLanguageCache(this DistributedCache dc, ILanguage language)
+ {
+ if (language == null)
{
- dc.Refresh(RelationTypeCacheRefresher.UniqueId, id);
+ return;
}
- public static void RemoveRelationTypeCache(this DistributedCache dc, int id)
- {
- dc.Remove(RelationTypeCacheRefresher.UniqueId, id);
- }
+ var payload = new LanguageCacheRefresher.JsonPayload(language.Id, language.IsoCode, LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove);
+ dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, new[] { payload });
+ }
- #endregion
+ #endregion
+ #region Relation type cache
+
+ public static void RefreshRelationTypeCache(this DistributedCache dc, int id)
+ {
+ dc.Refresh(RelationTypeCacheRefresher.UniqueId, id);
+ }
+ public static void RemoveRelationTypeCache(this DistributedCache dc, int id)
+ {
+ dc.Remove(RelationTypeCacheRefresher.UniqueId, id);
}
+
+ #endregion
+
}
diff --git a/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs
index 34cdd3ce0c4d..91ae85c84f68 100644
--- a/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs
+++ b/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs
@@ -1,187 +1,191 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System;
-using System.Collections.Generic;
-using System.Linq;
using Umbraco.Cms.Core.Collections;
using Umbraco.Cms.Core.Models.Entities;
-using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Infrastructure.Scoping;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+
+///
+/// Represents a caching policy that caches the entire entities set as a single collection.
+///
+/// The type of the entity.
+/// The type of the identifier.
+///
+/// Caches the entire set of entities as a single collection.
+///
+/// Used by Content-, Media- and MemberTypeRepository, DataTypeRepository, DomainRepository,
+/// LanguageRepository, PublicAccessRepository, TemplateRepository... things that make sense to
+/// keep as a whole in memory.
+///
+///
+internal class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase
+ where TEntity : class, IEntity
{
- ///
- /// Represents a caching policy that caches the entire entities set as a single collection.
- ///
- /// The type of the entity.
- /// The type of the identifier.
- ///
- /// Caches the entire set of entities as a single collection.
- /// Used by Content-, Media- and MemberTypeRepository, DataTypeRepository, DomainRepository,
- /// LanguageRepository, PublicAccessRepository, TemplateRepository... things that make sense to
- /// keep as a whole in memory.
- ///
- internal class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase
- where TEntity : class, IEntity
+ protected static readonly TId[] EmptyIds = new TId[0]; // const
+ private readonly Func _entityGetId;
+ private readonly bool _expires;
+
+ public FullDataSetRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires)
+ : base(cache, scopeAccessor)
{
- private readonly Func _entityGetId;
- private readonly bool _expires;
+ _entityGetId = entityGetId;
+ _expires = expires;
+ }
- public FullDataSetRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires)
- : base(cache, scopeAccessor)
+ ///
+ public override void Create(TEntity entity, Action persistNew)
+ {
+ if (entity == null)
{
- _entityGetId = entityGetId;
- _expires = expires;
+ throw new ArgumentNullException(nameof(entity));
}
- protected static readonly TId[] EmptyIds = new TId[0]; // const
-
- protected string GetEntityTypeCacheKey()
+ try
{
- return $"uRepo_{typeof (TEntity).Name}_";
+ persistNew(entity);
}
-
- protected void InsertEntities(TEntity[]? entities)
+ finally
{
- if (entities is null)
- {
- return;
- }
-
- // cache is expected to be a deep-cloning cache ie it deep-clones whatever is
- // IDeepCloneable when it goes in, and out. it also resets dirty properties,
- // making sure that no 'dirty' entity is cached.
- //
- // this policy is caching the entire list of entities. to ensure that entities
- // are properly deep-clones when cached, it uses a DeepCloneableList. however,
- // we don't want to deep-clone *each* entity in the list when fetching it from
- // cache as that would not be efficient for Get(id). so the DeepCloneableList is
- // set to ListCloneBehavior.CloneOnce ie it will clone *once* when inserting,
- // and then will *not* clone when retrieving.
-
- var key = GetEntityTypeCacheKey();
-
- if (_expires)
- {
- Cache.Insert(key, () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true);
- }
- else
- {
- Cache.Insert(key, () => new DeepCloneableList(entities));
- }
+ ClearAll();
}
+ }
+
+ protected string GetEntityTypeCacheKey() => $"uRepo_{typeof(TEntity).Name}_";
- ///
- public override void Create(TEntity entity, Action persistNew)
+ protected void InsertEntities(TEntity[]? entities)
+ {
+ if (entities is null)
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
-
- try
- {
- persistNew(entity);
- }
- finally
- {
- ClearAll();
- }
+ return;
}
- ///
- public override void Update(TEntity entity, Action persistUpdated)
+ // cache is expected to be a deep-cloning cache ie it deep-clones whatever is
+ // IDeepCloneable when it goes in, and out. it also resets dirty properties,
+ // making sure that no 'dirty' entity is cached.
+ //
+ // this policy is caching the entire list of entities. to ensure that entities
+ // are properly deep-clones when cached, it uses a DeepCloneableList. however,
+ // we don't want to deep-clone *each* entity in the list when fetching it from
+ // cache as that would not be efficient for Get(id). so the DeepCloneableList is
+ // set to ListCloneBehavior.CloneOnce ie it will clone *once* when inserting,
+ // and then will *not* clone when retrieving.
+ var key = GetEntityTypeCacheKey();
+
+ if (_expires)
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
-
- try
- {
- persistUpdated(entity);
- }
- finally
- {
- ClearAll();
- }
+ Cache.Insert(key, () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true);
}
-
- ///
- public override void Delete(TEntity entity, Action persistDeleted)
+ else
{
- if (entity == null) throw new ArgumentNullException(nameof(entity));
-
- try
- {
- persistDeleted(entity);
- }
- finally
- {
- ClearAll();
- }
+ Cache.Insert(key, () => new DeepCloneableList(entities));
}
+ }
- ///
- public override TEntity? Get(TId? id, Func performGet, Func?> performGetAll)
+ ///
+ public override void Update(TEntity entity, Action persistUpdated)
+ {
+ if (entity == null)
{
- // get all from the cache, then look for the entity
- var all = GetAllCached(performGetAll);
- var entity = all.FirstOrDefault(x => _entityGetId(x)?.Equals(id) ?? false);
-
- // see note in InsertEntities - what we get here is the original
- // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
- return (TEntity?)entity?.DeepClone();
+ throw new ArgumentNullException(nameof(entity));
}
- ///
- public override TEntity? GetCached(TId id)
+ try
{
- // get all from the cache -- and only the cache, then look for the entity
- var all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
- var entity = all?.FirstOrDefault(x => _entityGetId(x)?.Equals(id) ?? false);
-
- // see note in InsertEntities - what we get here is the original
- // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
- return (TEntity?) entity?.DeepClone();
+ persistUpdated(entity);
+ }
+ finally
+ {
+ ClearAll();
}
+ }
- ///
- public override bool Exists(TId id, Func performExits, Func?> performGetAll)
+ ///
+ public override void Delete(TEntity entity, Action persistDeleted)
+ {
+ if (entity == null)
{
- // get all as one set, then look for the entity
- var all = GetAllCached(performGetAll);
- return all.Any(x => _entityGetId(x)?.Equals(id) ?? false);
+ throw new ArgumentNullException(nameof(entity));
}
- ///
- public override TEntity[] GetAll(TId[]? ids, Func?> performGetAll)
+ try
+ {
+ persistDeleted(entity);
+ }
+ finally
{
- // get all as one set, from cache if possible, else repo
- var all = GetAllCached(performGetAll);
+ ClearAll();
+ }
+ }
- // if ids have been specified, filter
- if (ids?.Length > 0) all = all.Where(x => ids.Contains(_entityGetId(x)));
+ ///
+ public override TEntity? Get(TId? id, Func performGet, Func?> performGetAll)
+ {
+ // get all from the cache, then look for the entity
+ IEnumerable all = GetAllCached(performGetAll);
+ TEntity? entity = all.FirstOrDefault(x => _entityGetId(x)?.Equals(id) ?? false);
- // and return
- // see note in SetCacheActionToInsertEntities - what we get here is the original
- // cached entities, not clones, so we need to manually ensure they are deep-cloned.
- return all.Select(x => (TEntity) x.DeepClone()).ToArray();
- }
+ // see note in InsertEntities - what we get here is the original
+ // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
+ return (TEntity?)entity?.DeepClone();
+ }
- // does NOT clone anything, so be nice with the returned values
- internal IEnumerable GetAllCached(Func?> performGetAll)
+ ///
+ public override TEntity? GetCached(TId id)
+ {
+ // get all from the cache -- and only the cache, then look for the entity
+ DeepCloneableList? all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
+ TEntity? entity = all?.FirstOrDefault(x => _entityGetId(x)?.Equals(id) ?? false);
+
+ // see note in InsertEntities - what we get here is the original
+ // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
+ return (TEntity?)entity?.DeepClone();
+ }
+
+ ///
+ public override bool Exists(TId id, Func performExits, Func?> performGetAll)
+ {
+ // get all as one set, then look for the entity
+ IEnumerable all = GetAllCached(performGetAll);
+ return all.Any(x => _entityGetId(x)?.Equals(id) ?? false);
+ }
+
+ ///
+ public override TEntity[] GetAll(TId[]? ids, Func?> performGetAll)
+ {
+ // get all as one set, from cache if possible, else repo
+ IEnumerable all = GetAllCached(performGetAll);
+
+ // if ids have been specified, filter
+ if (ids?.Length > 0)
{
- // try the cache first
- var all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
- if (all != null) return all.ToArray();
-
- // else get from repo and cache
- var entities = performGetAll(EmptyIds)?.WhereNotNull().ToArray();
- InsertEntities(entities); // may be an empty array...
- return entities ?? Enumerable.Empty();
+ all = all.Where(x => ids.Contains(_entityGetId(x)));
}
- ///
- public override void ClearAll()
+ // and return
+ // see note in SetCacheActionToInsertEntities - what we get here is the original
+ // cached entities, not clones, so we need to manually ensure they are deep-cloned.
+ return all.Select(x => (TEntity)x.DeepClone()).ToArray();
+ }
+
+ ///
+ public override void ClearAll() => Cache.Clear(GetEntityTypeCacheKey());
+
+ // does NOT clone anything, so be nice with the returned values
+ internal IEnumerable GetAllCached(Func?> performGetAll)
+ {
+ // try the cache first
+ DeepCloneableList? all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
+ if (all != null)
{
- Cache.Clear(GetEntityTypeCacheKey());
+ return all.ToArray();
}
+
+ // else get from repo and cache
+ TEntity[]? entities = performGetAll(EmptyIds)?.WhereNotNull().ToArray();
+ InsertEntities(entities); // may be an empty array...
+ return entities ?? Enumerable.Empty();
}
}
diff --git a/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs
index 900ff02921a8..7a43071b813e 100644
--- a/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs
+++ b/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs
@@ -1,72 +1,71 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System;
-using System.Collections.Generic;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Infrastructure.Scoping;
+using IScope = Umbraco.Cms.Infrastructure.Scoping.IScope;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+
+///
+/// A base class for repository cache policies.
+///
+/// The type of the entity.
+/// The type of the identifier.
+public abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy
+ where TEntity : class, IEntity
{
- ///
- /// A base class for repository cache policies.
- ///
- /// The type of the entity.
- /// The type of the identifier.
- public abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy
- where TEntity : class, IEntity
- {
- private readonly IAppPolicyCache _globalCache;
- private readonly IScopeAccessor _scopeAccessor;
+ private readonly IAppPolicyCache _globalCache;
+ private readonly IScopeAccessor _scopeAccessor;
- protected RepositoryCachePolicyBase(IAppPolicyCache globalCache, IScopeAccessor scopeAccessor)
- {
- _globalCache = globalCache ?? throw new ArgumentNullException(nameof(globalCache));
- _scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor));
- }
+ protected RepositoryCachePolicyBase(IAppPolicyCache globalCache, IScopeAccessor scopeAccessor)
+ {
+ _globalCache = globalCache ?? throw new ArgumentNullException(nameof(globalCache));
+ _scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor));
+ }
- protected IAppPolicyCache Cache
+ protected IAppPolicyCache Cache
+ {
+ get
{
- get
+ IScope? ambientScope = _scopeAccessor.AmbientScope;
+ switch (ambientScope?.RepositoryCacheMode)
{
- var ambientScope = _scopeAccessor.AmbientScope;
- switch (ambientScope?.RepositoryCacheMode)
- {
- case RepositoryCacheMode.Default:
- return _globalCache;
- case RepositoryCacheMode.Scoped:
- return ambientScope.IsolatedCaches.GetOrCreate();
- case RepositoryCacheMode.None:
- return NoAppCache.Instance;
- default:
- throw new NotSupportedException($"Repository cache mode {ambientScope?.RepositoryCacheMode} is not supported.");
- }
+ case RepositoryCacheMode.Default:
+ return _globalCache;
+ case RepositoryCacheMode.Scoped:
+ return ambientScope.IsolatedCaches.GetOrCreate();
+ case RepositoryCacheMode.None:
+ return NoAppCache.Instance;
+ default:
+ throw new NotSupportedException(
+ $"Repository cache mode {ambientScope?.RepositoryCacheMode} is not supported.");
}
}
+ }
- ///
- public abstract TEntity? Get(TId? id, Func performGet, Func?> performGetAll);
+ ///
+ public abstract TEntity? Get(TId? id, Func performGet, Func?> performGetAll);
- ///
- public abstract TEntity? GetCached(TId id);
+ ///
+ public abstract TEntity? GetCached(TId id);
- ///
- public abstract bool Exists(TId id, Func performExists, Func?> performGetAll);
+ ///
+ public abstract bool Exists(TId id, Func performExists, Func?> performGetAll);
- ///
- public abstract void Create(TEntity entity, Action persistNew);
+ ///
+ public abstract void Create(TEntity entity, Action persistNew);
- ///
- public abstract void Update(TEntity entity, Action persistUpdated);
+ ///
+ public abstract void Update(TEntity entity, Action persistUpdated);
- ///
- public abstract void Delete(TEntity entity, Action persistDeleted);
+ ///
+ public abstract void Delete(TEntity entity, Action persistDeleted);
- ///
- public abstract TEntity[] GetAll(TId[]? ids, Func?> performGetAll);
+ ///
+ public abstract TEntity[] GetAll(TId[]? ids, Func?> performGetAll);
- ///
- public abstract void ClearAll();
- }
+ ///
+ public abstract void ClearAll();
}
diff --git a/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
index d23960c90328..16079d059a4a 100644
--- a/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
+++ b/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
@@ -2,31 +2,32 @@
// See LICENSE for more details.
using Umbraco.Cms.Core.Models.Entities;
-using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Infrastructure.Scoping;
-namespace Umbraco.Cms.Core.Cache
+namespace Umbraco.Cms.Core.Cache;
+
+///
+/// Represents a special policy that does not cache the result of GetAll.
+///
+/// The type of the entity.
+/// The type of the identifier.
+///
+///
+/// Overrides the default repository cache policy and does not writes the result of GetAll
+/// to cache, but only the result of individual Gets. It does read the cache for GetAll, though.
+///
+/// Used by DictionaryRepository.
+///
+internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy
+ where TEntity : class, IEntity
{
- ///
- /// Represents a special policy that does not cache the result of GetAll.
- ///
- /// The type of the entity.
- /// The type of the identifier.
- ///
- /// Overrides the default repository cache policy and does not writes the result of GetAll
- /// to cache, but only the result of individual Gets. It does read the cache for GetAll, though.
- /// Used by DictionaryRepository.
- ///
- internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy
- where TEntity : class, IEntity
+ public SingleItemsOnlyRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options)
+ : base(cache, scopeAccessor, options)
{
- public SingleItemsOnlyRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options)
- : base(cache, scopeAccessor, options)
- { }
+ }
- protected override void InsertEntities(TId[]? ids, TEntity[]? entities)
- {
- // nop
- }
+ protected override void InsertEntities(TId[]? ids, TEntity[]? entities)
+ {
+ // nop
}
}
diff --git a/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs b/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs
index fe2114163661..09cd2282da62 100644
--- a/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs
+++ b/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs
@@ -1,24 +1,20 @@
-using System;
using NCrontab;
-using Umbraco.Cms.Core.Configuration;
-namespace Umbraco.Cms.Core.Configuration
+namespace Umbraco.Cms.Core.Configuration;
+
+public class NCronTabParser : ICronTabParser
{
- public class NCronTabParser : ICronTabParser
+ public bool IsValidCronTab(string cronTab)
{
- public bool IsValidCronTab(string cronTab)
- {
- var result = CrontabSchedule.TryParse(cronTab);
+ var result = CrontabSchedule.TryParse(cronTab);
- return !(result is null);
- }
+ return !(result is null);
+ }
- public DateTime GetNextOccurrence(string cronTab, DateTime time)
- {
- var result = CrontabSchedule.Parse(cronTab);
+ public DateTime GetNextOccurrence(string cronTab, DateTime time)
+ {
+ var result = CrontabSchedule.Parse(cronTab);
- return result.GetNextOccurrence(time);
- }
+ return result.GetNextOccurrence(time);
}
-
}
diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
index 7091b89cadca..bc83695d9445 100644
--- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
+++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
@@ -3,30 +3,27 @@
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
-namespace Umbraco.Extensions
+namespace Umbraco.Extensions;
+
+///
+/// Provides extension methods to the class.
+///
+public static partial class UmbracoBuilderExtensions
{
///
- /// Provides extension methods to the class.
+ /// Gets the mappers collection builder.
///
- public static partial class UmbracoBuilderExtensions
- {
- ///
- /// Gets the mappers collection builder.
- ///
- /// The builder.
- public static MapperCollectionBuilder? Mappers(this IUmbracoBuilder builder)
- => builder.WithCollectionBuilder();
-
- public static NPocoMapperCollectionBuilder? NPocoMappers(this IUmbracoBuilder builder)
- => builder.WithCollectionBuilder();
-
+ /// The builder.
+ public static MapperCollectionBuilder? Mappers(this IUmbracoBuilder builder)
+ => builder.WithCollectionBuilder();
- ///
- /// Gets the package migration plans collection builder.
- ///
- /// The builder.
- public static PackageMigrationPlanCollectionBuilder? PackageMigrationPlans(this IUmbracoBuilder builder)
- => builder.WithCollectionBuilder();
+ public static NPocoMapperCollectionBuilder? NPocoMappers(this IUmbracoBuilder builder)
+ => builder.WithCollectionBuilder();
- }
+ ///
+ /// Gets the package migration plans collection builder.
+ ///
+ /// The builder.
+ public static PackageMigrationPlanCollectionBuilder? PackageMigrationPlans(this IUmbracoBuilder builder)
+ => builder.WithCollectionBuilder();
}
diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
index 4b30a10159bd..9252cb71119e 100644
--- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
+++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
@@ -3,6 +3,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Serilog;
+using SixLabors.ImageSharp;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration;
@@ -55,335 +56,345 @@
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Cms.Infrastructure.Services.Implement;
using Umbraco.Extensions;
+using IScopeProvider = Umbraco.Cms.Infrastructure.Scoping.IScopeProvider;
-namespace Umbraco.Cms.Infrastructure.DependencyInjection
+namespace Umbraco.Cms.Infrastructure.DependencyInjection;
+
+public static partial class UmbracoBuilderExtensions
{
- public static partial class UmbracoBuilderExtensions
+ ///
+ /// Adds all core Umbraco services required to run which may be replaced later in the pipeline
+ ///
+ public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder)
{
- ///
- /// Adds all core Umbraco services required to run which may be replaced later in the pipeline
- ///
- public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder)
- {
- builder
- .AddMainDom()
- .AddLogging();
+ builder
+ .AddMainDom()
+ .AddLogging();
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
- builder.Services.AddSingleton(factory => factory.GetRequiredService().SqlContext);
- builder.NPocoMappers()?.Add();
- builder.PackageMigrationPlans()?.Add(() => builder.TypeLoader.GetPackageMigrationPlans());
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton(factory => factory.GetRequiredService().SqlContext);
+ builder.NPocoMappers()?.Add();
+ builder.PackageMigrationPlans()?.Add(() => builder.TypeLoader.GetPackageMigrationPlans());
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
- builder.AddNotificationAsyncHandler();
- builder.AddNotificationAsyncHandler();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.AddNotificationAsyncHandler();
+ builder.AddNotificationAsyncHandler();
- // composers
- builder
- .AddRepositories()
- .AddServices()
- .AddCoreMappingProfiles()
- .AddFileSystems()
- .AddWebAssets();
+ // composers
+ builder
+ .AddRepositories()
+ .AddServices()
+ .AddCoreMappingProfiles()
+ .AddFileSystems()
+ .AddWebAssets();
- // register persistence mappers - required by database factory so needs to be done here
- // means the only place the collection can be modified is in a runtime - afterwards it
- // has been frozen and it is too late
- builder.Mappers()?.AddCoreMappers();
+ // register persistence mappers - required by database factory so needs to be done here
+ // means the only place the collection can be modified is in a runtime - afterwards it
+ // has been frozen and it is too late
+ builder.Mappers()?.AddCoreMappers();
- // register the scope provider
- builder.Services.AddSingleton(); // implements IScopeProvider, IScopeAccessor
- builder.Services.AddSingleton(f => f.GetRequiredService());
- builder.Services.AddSingleton(f => f.GetRequiredService());
- builder.Services.AddSingleton(f => f.GetRequiredService());
- builder.Services.AddSingleton(f => f.GetRequiredService());
+ // register the scope provider
+ builder.Services.AddSingleton(); // implements IScopeProvider, IScopeAccessor
+ builder.Services.AddSingleton(f => f.GetRequiredService());
+ builder.Services.AddSingleton(f => f.GetRequiredService());
+ builder.Services.AddSingleton(f => f.GetRequiredService());
+ builder.Services.AddSingleton(f => f.GetRequiredService());
- builder.Services.AddScoped();
+ builder.Services.AddScoped();
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
- // register database builder
- // *not* a singleton, don't want to keep it around
- builder.Services.AddTransient();
+ // register database builder
+ // *not* a singleton, don't want to keep it around
+ builder.Services.AddTransient();
- // register manifest parser, will be injected in collection builders where needed
- builder.Services.AddSingleton();
+ // register manifest parser, will be injected in collection builders where needed
+ builder.Services.AddSingleton();
- // register the manifest filter collection builder (collection is empty by default)
- builder.ManifestFilters();
+ // register the manifest filter collection builder (collection is empty by default)
+ builder.ManifestFilters();
- builder.MediaUrlGenerators()
- .Add()
- .Add();
+ builder.MediaUrlGenerators()
+ .Add()
+ .Add();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
- builder.Services.AddSingleton(factory
- => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().CurrentValue)));
+ builder.Services.AddSingleton