diff --git a/src/Umbraco.Core/Actions/ActionDocumentPropertyRead.cs b/src/Umbraco.Core/Actions/ActionDocumentPropertyRead.cs
index 65fe4932cc9b..9c9d9e3b093e 100644
--- a/src/Umbraco.Core/Actions/ActionDocumentPropertyRead.cs
+++ b/src/Umbraco.Core/Actions/ActionDocumentPropertyRead.cs
@@ -1,5 +1,11 @@
-namespace Umbraco.Cms.Core.Actions;
+namespace Umbraco.Cms.Core.Actions;
+///
+/// Represents the action that allows reading document property values.
+///
+///
+/// This action is used for permission control when accessing property values on documents.
+///
public class ActionDocumentPropertyRead : IAction
{
///
diff --git a/src/Umbraco.Core/Actions/ActionDocumentPropertyWrite.cs b/src/Umbraco.Core/Actions/ActionDocumentPropertyWrite.cs
index 8effd527aea1..b9221e11bf9f 100644
--- a/src/Umbraco.Core/Actions/ActionDocumentPropertyWrite.cs
+++ b/src/Umbraco.Core/Actions/ActionDocumentPropertyWrite.cs
@@ -1,5 +1,11 @@
-namespace Umbraco.Cms.Core.Actions;
+namespace Umbraco.Cms.Core.Actions;
+///
+/// Represents the action that allows writing document property values.
+///
+///
+/// This action is used for permission control when modifying property values on documents.
+///
public class ActionDocumentPropertyWrite : IAction
{
///
diff --git a/src/Umbraco.Core/Blocks/IPartialViewBlockEngine.cs b/src/Umbraco.Core/Blocks/IPartialViewBlockEngine.cs
index 3b462d086502..5763fdfdcd1d 100644
--- a/src/Umbraco.Core/Blocks/IPartialViewBlockEngine.cs
+++ b/src/Umbraco.Core/Blocks/IPartialViewBlockEngine.cs
@@ -1,9 +1,17 @@
-using Umbraco.Cms.Core.Models.Blocks;
+using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Cms.Core.Blocks;
+///
+/// Defines a contract for rendering block references using partial views.
+///
public interface IPartialViewBlockEngine
{
+ ///
+ /// Executes the partial view associated with the given block reference and returns the rendered output.
+ ///
+ /// The block reference containing content and settings elements to render.
+ /// A task that represents the asynchronous operation. The task result contains the rendered HTML string.
Task ExecuteAsync(IBlockReference blockReference);
}
diff --git a/src/Umbraco.Core/Cache/AppCacheExtensions.cs b/src/Umbraco.Core/Cache/AppCacheExtensions.cs
index 32c1b772f014..435b48d7f8a5 100644
--- a/src/Umbraco.Core/Cache/AppCacheExtensions.cs
+++ b/src/Umbraco.Core/Cache/AppCacheExtensions.cs
@@ -3,10 +3,20 @@
namespace Umbraco.Extensions;
///
-/// Extensions for strongly typed access
+/// Provides extension methods for strongly typed access to and .
///
public static class AppCacheExtensions
{
+ ///
+ /// Gets a strongly typed cache item with the specified key, creating it if necessary using the provided factory.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// A factory function that creates the item if not found.
+ /// An optional cache timeout.
+ /// Whether the timeout is sliding (resets on access).
+ /// The cached item, or default if not found and factory returns null.
public static T? GetCacheItem(
this IAppPolicyCache provider,
string cacheKey,
@@ -18,6 +28,15 @@ public static class AppCacheExtensions
return result == null ? default : result.TryConvertTo().Result;
}
+ ///
+ /// Inserts a strongly typed cache item with the specified key.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// A factory function that creates the item to cache.
+ /// An optional cache timeout.
+ /// Whether the timeout is sliding (resets on access).
public static void InsertCacheItem(
this IAppPolicyCache provider,
string cacheKey,
@@ -26,18 +45,39 @@ public static void InsertCacheItem(
bool isSliding = false) =>
provider.Insert(cacheKey, () => getCacheItem(), timeout, isSliding);
+ ///
+ /// Gets strongly typed cache items with keys starting with the specified value.
+ ///
+ /// The type of the cached items.
+ /// The cache provider.
+ /// The key prefix to search for.
+ /// A collection of cached items matching the search.
public static IEnumerable GetCacheItemsByKeySearch(this IAppCache provider, string keyStartsWith)
{
IEnumerable result = provider.SearchByKey(keyStartsWith);
return result.Select(x => x.TryConvertTo().Result);
}
+ ///
+ /// Gets strongly typed cache items with keys matching a regular expression.
+ ///
+ /// The type of the cached items.
+ /// The cache provider.
+ /// The regular expression pattern to match keys against.
+ /// A collection of cached items matching the search.
public static IEnumerable GetCacheItemsByKeyExpression(this IAppCache provider, string regexString)
{
IEnumerable result = provider.SearchByRegex(regexString);
return result.Select(x => x.TryConvertTo().Result);
}
+ ///
+ /// Gets a strongly typed cache item with the specified key.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// The cached item, or default if not found.
public static T? GetCacheItem(this IAppCache provider, string cacheKey)
{
var result = provider.Get(cacheKey);
@@ -56,6 +96,14 @@ public static void InsertCacheItem(
return result.TryConvertTo().Result;
}
+ ///
+ /// Gets a strongly typed cache item with the specified key, creating it if necessary using the provided factory.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// A factory function that creates the item if not found.
+ /// The cached item, or default if not found and factory returns null.
public static T? GetCacheItem(this IAppCache provider, string cacheKey, Func getCacheItem)
{
var result = provider.Get(cacheKey, () => getCacheItem());
@@ -74,6 +122,16 @@ public static void InsertCacheItem(
return result.TryConvertTo().Result;
}
+ ///
+ /// Asynchronously gets a strongly typed cache item with the specified key, creating it if necessary using the provided factory.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// An async factory function that creates the item if not found.
+ /// An optional cache timeout.
+ /// Whether the timeout is sliding (resets on access).
+ /// A task representing the asynchronous operation, containing the cached item.
public static async Task GetCacheItemAsync(
this IAppPolicyCache provider,
string cacheKey,
@@ -108,6 +166,16 @@ public static void InsertCacheItem(
private static bool RequestedNullRepresentationInCache() => typeof(T) == typeof(string);
+ ///
+ /// Asynchronously inserts a strongly typed cache item with the specified key.
+ ///
+ /// The type of the cached item.
+ /// The cache provider.
+ /// The cache key.
+ /// An async factory function that creates the item to cache.
+ /// An optional cache timeout.
+ /// Whether the timeout is sliding (resets on access).
+ /// A task representing the asynchronous operation.
public static async Task InsertCacheItemAsync(
this IAppPolicyCache provider,
string cacheKey,
diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs
index 60c7d0ed2275..82a406906106 100644
--- a/src/Umbraco.Core/Cache/AppCaches.cs
+++ b/src/Umbraco.Core/Cache/AppCaches.cs
@@ -69,17 +69,27 @@ public AppCaches(
///
public IsolatedCaches IsolatedCaches { get; }
+ ///
+ /// Creates a new instance of with the specified request cache.
+ ///
+ /// The request cache to use.
+ /// A new instance.
public static AppCaches Create(IRequestCache requestCache) =>
new(
new DeepCloneAppCache(new ObjectCacheAppCache()),
requestCache,
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
+ ///
public void Dispose() =>
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(true);
+ ///
+ /// Releases the unmanaged resources used by the and optionally releases the managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
diff --git a/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs
index 788e95f90924..039ab9e6eb8f 100644
--- a/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs
+++ b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs
@@ -24,6 +24,7 @@ public abstract class AppPolicedCacheDictionary : IDisposable
///
protected AppPolicedCacheDictionary(Func cacheFactory) => _cacheFactory = cacheFactory;
+ ///
public void Dispose() =>
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
@@ -75,6 +76,10 @@ protected void ClearCache(TKey key)
}
}
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs
index 0e75b6820db5..49c0e6f8e553 100644
--- a/src/Umbraco.Core/Cache/CacheKeys.cs
+++ b/src/Umbraco.Core/Cache/CacheKeys.cs
@@ -1,27 +1,68 @@
namespace Umbraco.Cms.Core.Cache;
///
-/// Constants storing cache keys used in caching
+/// Constants storing cache keys used in caching.
///
public static class CacheKeys
{
- public const string ApplicationsCacheKey = "ApplicationCache"; // used by SectionService
+ ///
+ /// Cache key for applications (sections) cache, used by SectionService.
+ ///
+ public const string ApplicationsCacheKey = "ApplicationCache";
+ ///
+ /// Cache key prefix for template front-end cache.
+ ///
// TODO: this one can probably be removed
public const string TemplateFrontEndCacheKey = "template";
+ ///
+ /// Cache key prefix for user group lookup by alias.
+ ///
public const string UserGroupGetByAliasCacheKeyPrefix = "UserGroupRepository_GetByAlias_";
+ ///
+ /// Cache key prefix for user's content start nodes.
+ ///
public const string UserAllContentStartNodesPrefix = "AllContentStartNodes";
+
+ ///
+ /// Cache key prefix for user's media start nodes.
+ ///
public const string UserAllMediaStartNodesPrefix = "AllMediaStartNodes";
+
+ ///
+ /// Cache key prefix for user's media start node paths.
+ ///
public const string UserMediaStartNodePathsPrefix = "MediaStartNodePaths";
+
+ ///
+ /// Cache key prefix for user's content start node paths.
+ ///
public const string UserContentStartNodePathsPrefix = "ContentStartNodePaths";
+ ///
+ /// Cache key for content recycle bin.
+ ///
public const string ContentRecycleBinCacheKey = "recycleBin_content";
+
+ ///
+ /// Cache key for media recycle bin.
+ ///
public const string MediaRecycleBinCacheKey = "recycleBin_media";
+ ///
+ /// Cache key prefix for preview (draft) property cache values.
+ ///
public const string PreviewPropertyCacheKeyPrefix = "Cache.Property.CacheValues[D:";
+
+ ///
+ /// Cache key prefix for published property cache values.
+ ///
public const string PropertyCacheKeyPrefix = "Cache.Property.CacheValues[P:";
+ ///
+ /// Cache key prefix for member username lookups.
+ ///
public const string MemberUserNameCachePrefix = "uRepo_userNameKey+";
}
diff --git a/src/Umbraco.Core/Cache/DataTypeConfigurationCache.cs b/src/Umbraco.Core/Cache/DataTypeConfigurationCache.cs
index 70c9b4161be9..f7b99a755408 100644
--- a/src/Umbraco.Core/Cache/DataTypeConfigurationCache.cs
+++ b/src/Umbraco.Core/Cache/DataTypeConfigurationCache.cs
@@ -6,20 +6,32 @@
namespace Umbraco.Cms.Core.Cache;
///
-/// This cache is a temporary measure to reduce the amount of computational power required to deserialize and initialize when fetched from the main cache/database,
-/// because datatypes are fetched multiple times troughout a (backoffice content) request with a lot of content (or nested content) and each of these fetches initializes certain fields on the datatypes.
+/// Implements to cache data type configurations.
///
+///
+/// This cache is a temporary measure to reduce the amount of computational power required to
+/// deserialize and initialize when fetched from the main cache/database,
+/// because data types are fetched multiple times throughout a (backoffice content) request with
+/// a lot of content (or nested content) and each of these fetches initializes certain fields on the data types.
+///
internal sealed class DataTypeConfigurationCache : IDataTypeConfigurationCache
{
private readonly IDataTypeService _dataTypeService;
private readonly IMemoryCache _memoryCache;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The data type service.
+ /// The memory cache.
+ /// The ID/key map service.
public DataTypeConfigurationCache(IDataTypeService dataTypeService, IMemoryCache memoryCache, IIdKeyMap idKeyMap)
{
_dataTypeService = dataTypeService;
_memoryCache = memoryCache;
}
+ ///
public T? GetConfigurationAs(Guid key)
where T : class
{
@@ -39,6 +51,7 @@ public DataTypeConfigurationCache(IDataTypeService dataTypeService, IMemoryCache
return configuration;
}
+ ///
public void ClearCache(IEnumerable keys)
{
foreach (Guid key in keys)
diff --git a/src/Umbraco.Core/Cache/DataTypeConfigurationCacheRefresher.cs b/src/Umbraco.Core/Cache/DataTypeConfigurationCacheRefresher.cs
index 071acc795f4d..68311f748ef4 100644
--- a/src/Umbraco.Core/Cache/DataTypeConfigurationCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/DataTypeConfigurationCacheRefresher.cs
@@ -3,13 +3,25 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Handles to clear the data type configuration cache.
+///
+///
+/// This handler ensures that the is cleared when
+/// data types are modified, keeping cached configurations in sync with the database.
+///
internal sealed class DataTypeConfigurationCacheRefresher : INotificationHandler
{
private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The data type configuration cache.
public DataTypeConfigurationCacheRefresher(IDataTypeConfigurationCache dataTypeConfigurationCache)
=> _dataTypeConfigurationCache = dataTypeConfigurationCache;
+ ///
public void Handle(DataTypeCacheRefresherNotification notification)
=> _dataTypeConfigurationCache.ClearCache(((DataTypeCacheRefresher.JsonPayload[])notification.MessageObject).Select(x => x.Key));
}
diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
index ae9fb11c967c..4de30422466f 100644
--- a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
+++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
@@ -124,11 +124,16 @@ public void Insert(string key, Func factory, TimeSpan? timeout = null,
///
public void ClearByRegex(string regex) => InnerCache.ClearByRegex(regex);
+ ///
public void Dispose() =>
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(true);
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
diff --git a/src/Umbraco.Core/Cache/DictionaryAppCache.cs b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
index fa0ec1b0e0b2..f7a9cd0320e4 100644
--- a/src/Umbraco.Core/Cache/DictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
@@ -1,4 +1,4 @@
-using System.Collections;
+using System.Collections;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using Umbraco.Extensions;
@@ -15,6 +15,9 @@ public class DictionaryAppCache : IRequestCache
///
private readonly ConcurrentDictionary _items = new();
+ ///
+ /// Gets the number of items in the cache.
+ ///
public int Count => _items.Count;
///
@@ -38,8 +41,10 @@ public class DictionaryAppCache : IRequestCache
return null;
}
+ ///
public bool Set(string key, object? value) => _items.TryAdd(key, value);
+ ///
public bool Remove(string key) => _items.TryRemove(key, out _);
///
@@ -109,7 +114,12 @@ public virtual void ClearByRegex(string regex)
_items.RemoveAll(kvp => compiled.IsMatch(kvp.Key));
}
+ ///
+ /// Returns an enumerator that iterates through the cache items.
+ ///
+ /// An enumerator for the cache items.
public IEnumerator> GetEnumerator() => _items.GetEnumerator();
+ ///
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
diff --git a/src/Umbraco.Core/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Core/Cache/DistributedCacheExtensions.cs
index 3786951370e4..d08cf004c685 100644
--- a/src/Umbraco.Core/Cache/DistributedCacheExtensions.cs
+++ b/src/Umbraco.Core/Cache/DistributedCacheExtensions.cs
@@ -16,6 +16,10 @@ public static class DistributedCacheExtensions
{
#region PublicAccessCacheRefresher
+ ///
+ /// Refreshes all public access entries in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshPublicAccess(this DistributedCache dc)
=> dc.RefreshAll(PublicAccessCacheRefresher.UniqueId);
@@ -23,6 +27,11 @@ public static void RefreshPublicAccess(this DistributedCache dc)
#region UserCacheRefresher
+ ///
+ /// Removes the specified users from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The users to remove from cache.
public static void RemoveUserCache(this DistributedCache dc, IEnumerable users)
{
IEnumerable payloads = users.Select(x => new UserCacheRefresher.JsonPayload()
@@ -34,6 +43,11 @@ public static void RemoveUserCache(this DistributedCache dc, IEnumerable
dc.RefreshByPayload(UserCacheRefresher.UniqueId, payloads);
}
+ ///
+ /// Refreshes the specified users in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The users to refresh in cache.
public static void RefreshUserCache(this DistributedCache dc, IEnumerable users)
{
IEnumerable payloads = users.Select(x => new UserCacheRefresher.JsonPayload()
@@ -45,6 +59,10 @@ public static void RefreshUserCache(this DistributedCache dc, IEnumerable
dc.RefreshByPayload(UserCacheRefresher.UniqueId, payloads);
}
+ ///
+ /// Refreshes all users in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshAllUserCache(this DistributedCache dc)
=> dc.RefreshAll(UserCacheRefresher.UniqueId);
@@ -52,18 +70,42 @@ public static void RefreshAllUserCache(this DistributedCache dc)
#region UserGroupCacheRefresher
+ ///
+ /// Removes a user group from the distributed cache by user identifier.
+ ///
+ /// The distributed cache.
+ /// The user identifier.
public static void RemoveUserGroupCache(this DistributedCache dc, int userId)
=> dc.Remove(UserGroupCacheRefresher.UniqueId, userId);
+ ///
+ /// Removes the specified user groups from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The user groups to remove from cache.
public static void RemoveUserGroupCache(this DistributedCache dc, IEnumerable userGroups)
=> dc.Remove(UserGroupCacheRefresher.UniqueId, userGroups.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Refreshes a user group in the distributed cache by user identifier.
+ ///
+ /// The distributed cache.
+ /// The user identifier.
public static void RefreshUserGroupCache(this DistributedCache dc, int userId)
=> dc.Refresh(UserGroupCacheRefresher.UniqueId, userId);
+ ///
+ /// Refreshes the specified user groups in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The user groups to refresh in cache.
public static void RefreshUserGroupCache(this DistributedCache dc, IEnumerable userGroups)
=> dc.Refresh(UserGroupCacheRefresher.UniqueId, userGroups.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Refreshes all user groups in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshAllUserGroupCache(this DistributedCache dc)
=> dc.RefreshAll(UserGroupCacheRefresher.UniqueId);
@@ -71,15 +113,35 @@ public static void RefreshAllUserGroupCache(this DistributedCache dc)
#region TemplateCacheRefresher
+ ///
+ /// Refreshes a template in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The template identifier.
public static void RefreshTemplateCache(this DistributedCache dc, int templateId)
=> dc.Refresh(TemplateCacheRefresher.UniqueId, templateId);
+ ///
+ /// Refreshes the specified templates in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The templates to refresh in cache.
public static void RefreshTemplateCache(this DistributedCache dc, IEnumerable templates)
=> dc.Refresh(TemplateCacheRefresher.UniqueId, templates.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Removes a template from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The template identifier.
public static void RemoveTemplateCache(this DistributedCache dc, int templateId)
=> dc.Remove(TemplateCacheRefresher.UniqueId, templateId);
+ ///
+ /// Removes the specified templates from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The templates to remove from cache.
public static void RemoveTemplateCache(this DistributedCache dc, IEnumerable templates)
=> dc.Remove(TemplateCacheRefresher.UniqueId, templates.Select(x => x.Id).Distinct().ToArray());
@@ -87,15 +149,35 @@ public static void RemoveTemplateCache(this DistributedCache dc, IEnumerable
+ /// Refreshes a dictionary item in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The dictionary item identifier.
public static void RefreshDictionaryCache(this DistributedCache dc, int dictionaryItemId)
=> dc.Refresh(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
+ ///
+ /// Refreshes the specified dictionary items in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The dictionary items to refresh in cache.
public static void RefreshDictionaryCache(this DistributedCache dc, IEnumerable dictionaryItems)
=> dc.Refresh(DictionaryCacheRefresher.UniqueId, dictionaryItems.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Removes a dictionary item from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The dictionary item identifier.
public static void RemoveDictionaryCache(this DistributedCache dc, int dictionaryItemId)
=> dc.Remove(DictionaryCacheRefresher.UniqueId, dictionaryItemId);
+ ///
+ /// Removes the specified dictionary items from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The dictionary items to remove from cache.
public static void RemoveDictionaryCache(this DistributedCache dc, IEnumerable dictionaryItems)
=> dc.Remove(DictionaryCacheRefresher.UniqueId, dictionaryItems.Select(x => x.Id).Distinct().ToArray());
@@ -103,9 +185,19 @@ public static void RemoveDictionaryCache(this DistributedCache dc, IEnumerable
+ /// Refreshes the specified data types in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The data types to refresh in cache.
public static void RefreshDataTypeCache(this DistributedCache dc, IEnumerable dataTypes)
=> dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, dataTypes.DistinctBy(x => (x.Id, x.Key)).Select(x => new DataTypeCacheRefresher.JsonPayload(x.Id, x.Key, false)));
+ ///
+ /// Removes the specified data types from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The data types to remove from cache.
public static void RemoveDataTypeCache(this DistributedCache dc, IEnumerable dataTypes)
=> dc.RefreshByPayload(DataTypeCacheRefresher.UniqueId, dataTypes.DistinctBy(x => (x.Id, x.Key)).Select(x => new DataTypeCacheRefresher.JsonPayload(x.Id, x.Key, true)));
@@ -113,6 +205,11 @@ public static void RemoveDataTypeCache(this DistributedCache dc, IEnumerable
+ /// Refreshes the value editor cache for the specified data types.
+ ///
+ /// The distributed cache.
+ /// The data types whose value editors should be refreshed.
public static void RefreshValueEditorCache(this DistributedCache dc, IEnumerable dataTypes)
=> dc.RefreshByPayload(ValueEditorCacheRefresher.UniqueId, dataTypes.DistinctBy(x => (x.Id, x.Key)).Select(x => new DataTypeCacheRefresher.JsonPayload(x.Id, x.Key, false)));
@@ -120,6 +217,10 @@ public static void RefreshValueEditorCache(this DistributedCache dc, IEnumerable
#region ContentCacheRefresher
+ ///
+ /// Refreshes all content in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshAllContentCache(this DistributedCache dc)
{
ContentCacheRefresher.JsonPayload[] payloads = new[]
@@ -134,6 +235,11 @@ public static void RefreshAllContentCache(this DistributedCache dc)
dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
}
+ ///
+ /// Refreshes the content cache for the specified content changes.
+ ///
+ /// The distributed cache.
+ /// The content changes to refresh.
public static void RefreshContentCache(this DistributedCache dc, IEnumerable> changes)
{
IEnumerable payloads = changes.Select(x => new ContentCacheRefresher.JsonPayload()
@@ -153,25 +259,54 @@ public static void RefreshContentCache(this DistributedCache dc, IEnumerable
+ /// Refreshes the specified members in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The members to refresh in cache.
[Obsolete("Please use the overload taking all parameters. Scheduled for removal in Umbraco 18.")]
public static void RefreshMemberCache(this DistributedCache dc, IEnumerable members)
=> dc.RefreshMemberCache(members, new Dictionary());
+ ///
+ /// Refreshes the specified members in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The members to refresh in cache.
+ /// The notification state.
public static void RefreshMemberCache(this DistributedCache dc, IEnumerable members, IDictionary state)
=> dc.RefreshByPayload(
MemberCacheRefresher.UniqueId,
GetPayloads(members, state, false));
+ ///
+ /// Removes the specified members from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The members to remove from cache.
[Obsolete("Please use the overload taking all parameters. Scheduled for removal in Umbraco 18.")]
public static void RemoveMemberCache(this DistributedCache dc, IEnumerable members)
=> dc.RemoveMemberCache(members, new Dictionary());
+ ///
+ /// Removes the specified members from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The members to remove from cache.
+ /// The notification state.
public static void RemoveMemberCache(this DistributedCache dc, IEnumerable members, IDictionary state)
=> dc.RefreshByPayload(
MemberCacheRefresher.UniqueId,
GetPayloads(members, state, true));
- // Internal for unit test.
+ ///
+ /// Gets the JSON payloads for member cache refresh operations.
+ ///
+ /// The members to create payloads for.
+ /// The notification state dictionary.
+ /// Whether the members were removed.
+ /// An enumerable of JSON payloads for the member cache refresher.
+ /// Internal for unit test.
internal static IEnumerable GetPayloads(IEnumerable members, IDictionary state, bool removed)
=> members
.DistinctBy(x => (x.Id, x.Username))
@@ -201,15 +336,35 @@ public static void RemoveMemberCache(this DistributedCache dc, IEnumerable
+ /// Refreshes a member group in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The member group identifier.
public static void RefreshMemberGroupCache(this DistributedCache dc, int memberGroupId)
=> dc.Refresh(MemberGroupCacheRefresher.UniqueId, memberGroupId);
+ ///
+ /// Refreshes the specified member groups in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The member groups to refresh in cache.
public static void RefreshMemberGroupCache(this DistributedCache dc, IEnumerable memberGroups)
=> dc.Refresh(MemberGroupCacheRefresher.UniqueId, memberGroups.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Removes a member group from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The member group identifier.
public static void RemoveMemberGroupCache(this DistributedCache dc, int memberGroupId)
=> dc.Remove(MemberGroupCacheRefresher.UniqueId, memberGroupId);
+ ///
+ /// Removes the specified member groups from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The member groups to remove from cache.
public static void RemoveMemberGroupCache(this DistributedCache dc, IEnumerable memberGroups)
=> dc.Remove(MemberGroupCacheRefresher.UniqueId, memberGroups.Select(x => x.Id).Distinct().ToArray());
@@ -217,11 +372,19 @@ public static void RemoveMemberGroupCache(this DistributedCache dc, IEnumerable<
#region MediaCacheRefresher
+ ///
+ /// Refreshes all media in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshAllMediaCache(this DistributedCache dc)
// note: refresh all media cache does refresh content types too
=> dc.RefreshByPayload(MediaCacheRefresher.UniqueId, new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll).Yield());
-
+ ///
+ /// Refreshes the media cache for the specified media changes.
+ ///
+ /// The distributed cache.
+ /// The media changes to refresh.
public static void RefreshMediaCache(this DistributedCache dc, IEnumerable> changes)
=> dc.RefreshByPayload(MediaCacheRefresher.UniqueId, changes.DistinctBy(x => (x.Item.Id, x.Item.Key, x.ChangeTypes)).Select(x => new MediaCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes)));
@@ -229,6 +392,10 @@ public static void RefreshMediaCache(this DistributedCache dc, IEnumerable
+ /// Refreshes all published snapshots including content, media, and domain caches.
+ ///
+ /// The distributed cache.
public static void RefreshAllPublishedSnapshot(this DistributedCache dc)
{
// note: refresh all content & media caches does refresh content types too
@@ -241,12 +408,27 @@ public static void RefreshAllPublishedSnapshot(this DistributedCache dc)
#region ContentTypeCacheRefresher
+ ///
+ /// Refreshes the content type cache for the specified content type changes.
+ ///
+ /// The distributed cache.
+ /// The content type changes to refresh.
public static void RefreshContentTypeCache(this DistributedCache dc, IEnumerable> changes)
=> dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, changes.DistinctBy(x => (x.Item.Id, x.ChangeTypes)).Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IContentType).Name, x.Item.Id, x.ChangeTypes)));
+ ///
+ /// Refreshes the content type cache for the specified media type changes.
+ ///
+ /// The distributed cache.
+ /// The media type changes to refresh.
public static void RefreshContentTypeCache(this DistributedCache dc, IEnumerable> changes)
=> dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, changes.DistinctBy(x => (x.Item.Id, x.ChangeTypes)).Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMediaType).Name, x.Item.Id, x.ChangeTypes)));
+ ///
+ /// Refreshes the content type cache for the specified member type changes.
+ ///
+ /// The distributed cache.
+ /// The member type changes to refresh.
public static void RefreshContentTypeCache(this DistributedCache dc, IEnumerable> changes)
=> dc.RefreshByPayload(ContentTypeCacheRefresher.UniqueId, changes.DistinctBy(x => (x.Item.Id, x.ChangeTypes)).Select(x => new ContentTypeCacheRefresher.JsonPayload(typeof(IMemberType).Name, x.Item.Id, x.ChangeTypes)));
@@ -254,12 +436,26 @@ public static void RefreshContentTypeCache(this DistributedCache dc, IEnumerable
#region DomainCacheRefresher
+ ///
+ /// Refreshes the specified domains in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The domains to refresh in cache.
public static void RefreshDomainCache(this DistributedCache dc, IEnumerable domains)
=> dc.RefreshByPayload(DomainCacheRefresher.UniqueId, domains.DistinctBy(x => x.Id).Select(x => new DomainCacheRefresher.JsonPayload(x.Id, DomainChangeTypes.Refresh)));
+ ///
+ /// Removes the specified domains from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The domains to remove from cache.
public static void RemoveDomainCache(this DistributedCache dc, IEnumerable domains)
=> dc.RefreshByPayload(DomainCacheRefresher.UniqueId, domains.DistinctBy(x => x.Id).Select(x => new DomainCacheRefresher.JsonPayload(x.Id, DomainChangeTypes.Remove)));
+ ///
+ /// Refreshes all domains in the distributed cache.
+ ///
+ /// The distributed cache.
public static void RefreshAllDomainCache(this DistributedCache dc)
=> dc.RefreshByPayload(DomainCacheRefresher.UniqueId, new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll).Yield());
@@ -267,6 +463,11 @@ public static void RefreshAllDomainCache(this DistributedCache dc)
#region LanguageCacheRefresher
+ ///
+ /// Refreshes the specified languages in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The languages to refresh in cache.
public static void RefreshLanguageCache(this DistributedCache dc, IEnumerable languages)
=> dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, languages.DistinctBy(x => (x.Id, x.IsoCode)).Select(x => new LanguageCacheRefresher.JsonPayload(
x.Id,
@@ -275,6 +476,11 @@ public static void RefreshLanguageCache(this DistributedCache dc, IEnumerable
+ /// Removes the specified languages from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The languages to remove from cache.
public static void RemoveLanguageCache(this DistributedCache dc, IEnumerable languages)
=> dc.RefreshByPayload(LanguageCacheRefresher.UniqueId, languages.DistinctBy(x => (x.Id, x.IsoCode)).Select(x => new LanguageCacheRefresher.JsonPayload(x.Id, x.IsoCode, LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove)));
@@ -282,15 +488,35 @@ public static void RemoveLanguageCache(this DistributedCache dc, IEnumerable
+ /// Refreshes a relation type in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The relation type identifier.
public static void RefreshRelationTypeCache(this DistributedCache dc, int id)
=> dc.Refresh(RelationTypeCacheRefresher.UniqueId, id);
+ ///
+ /// Refreshes the specified relation types in the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The relation types to refresh in cache.
public static void RefreshRelationTypeCache(this DistributedCache dc, IEnumerable relationTypes)
=> dc.Refresh(RelationTypeCacheRefresher.UniqueId, relationTypes.Select(x => x.Id).Distinct().ToArray());
+ ///
+ /// Removes a relation type from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The relation type identifier.
public static void RemoveRelationTypeCache(this DistributedCache dc, int id)
=> dc.Remove(RelationTypeCacheRefresher.UniqueId, id);
+ ///
+ /// Removes the specified relation types from the distributed cache.
+ ///
+ /// The distributed cache.
+ /// The relation types to remove from cache.
public static void RemoveRelationTypeCache(this DistributedCache dc, IEnumerable relationTypes)
=> dc.Remove(RelationTypeCacheRefresher.UniqueId, relationTypes.Select(x => x.Id).Distinct().ToArray());
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
index e99cdad89986..9e94f014d587 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
@@ -14,8 +14,14 @@ public class FastDictionaryAppCache : IAppCache
///
private readonly ConcurrentDictionary> _items = new();
+ ///
+ /// Gets all cache keys.
+ ///
public IEnumerable Keys => _items.Keys;
+ ///
+ /// Gets the number of items in the cache.
+ ///
public int Count => _items.Count;
///
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
index 967d5aa5a70b..e46b1c660bfe 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
@@ -8,7 +8,9 @@ namespace Umbraco.Cms.Core.Cache;
///
public abstract class FastDictionaryAppCacheBase : IAppCache
{
- // prefix cache keys so we know which one are ours
+ ///
+ /// The prefix used for all cache keys to distinguish them from other cache entries.
+ ///
protected const string CacheItemPrefix = "umbrtmche";
#region IAppCache
@@ -264,26 +266,53 @@ public virtual void ClearByRegex(string regex)
#region Dictionary
- // manipulate the underlying cache entries
- // these *must* be called from within the appropriate locks
- // and use the full prefixed cache keys
+ ///
+ /// Gets all dictionary entries from the underlying cache.
+ ///
+ /// The dictionary entries.
+ /// Must be called from within the appropriate locks.
protected abstract IEnumerable> GetDictionaryEntries();
+ ///
+ /// Removes an entry from the underlying cache.
+ ///
+ /// The full prefixed cache key.
+ /// Must be called from within the appropriate locks.
protected abstract void RemoveEntry(string key);
+ ///
+ /// Gets an entry from the underlying cache.
+ ///
+ /// The full prefixed cache key.
+ /// The cached value, or null if not found.
+ /// Must be called from within the appropriate locks.
protected abstract object? GetEntry(string key);
- // read-write lock the underlying cache
- // protected abstract IDisposable ReadLock { get; }
- // protected abstract IDisposable WriteLock { get; }
+ ///
+ /// Enters a read lock on the underlying cache.
+ ///
protected abstract void EnterReadLock();
+ ///
+ /// Exits the read lock on the underlying cache.
+ ///
protected abstract void ExitReadLock();
+ ///
+ /// Enters a write lock on the underlying cache.
+ ///
protected abstract void EnterWriteLock();
+ ///
+ /// Exits the write lock on the underlying cache.
+ ///
protected abstract void ExitWriteLock();
+ ///
+ /// Gets the prefixed cache key.
+ ///
+ /// The public cache key.
+ /// The full prefixed cache key.
protected string GetCacheKey(string key) => $"{CacheItemPrefix}-{key}";
#endregion
diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
index 4352f9be31df..004c233a84ce 100644
--- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
@@ -2,6 +2,16 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Defines a repository cache policy for managing cached entities.
+///
+/// The type of the entity.
+/// The type of the entity identifier.
+///
+/// Repository cache policies control how repositories interact with caches,
+/// determining when to read from cache, when to populate cache, and how to
+/// keep caches in sync with the underlying data store.
+///
public interface IRepositoryCachePolicy
where TEntity : class, IEntity
{
diff --git a/src/Umbraco.Core/Cache/IRequestCache.cs b/src/Umbraco.Core/Cache/IRequestCache.cs
index f88bc3bb249c..3819e94cc3de 100644
--- a/src/Umbraco.Core/Cache/IRequestCache.cs
+++ b/src/Umbraco.Core/Cache/IRequestCache.cs
@@ -1,13 +1,34 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Defines a request-level cache that stores items for the duration of a single HTTP request.
+///
+///
+/// The request cache is designed to store transient data that is only valid within the context
+/// of a single HTTP request. Outside a web environment, the behavior of this cache is unspecified.
+///
public interface IRequestCache : IAppCache, IEnumerable>
{
///
- /// Returns true if the request cache is available otherwise false
+ /// Gets a value indicating whether the request cache is available.
///
+ ///
+ /// true if the request cache is available; otherwise, false .
+ ///
bool IsAvailable { get; }
+ ///
+ /// Sets a value in the request cache.
+ ///
+ /// The key of the item to set.
+ /// The value to store in the cache.
+ /// true if the value was set successfully; otherwise, false .
bool Set(string key, object? value);
+ ///
+ /// Removes a value from the request cache.
+ ///
+ /// The key of the item to remove.
+ /// true if the item was removed successfully; otherwise, false .
bool Remove(string key);
}
diff --git a/src/Umbraco.Core/Cache/IValueEditorCache.cs b/src/Umbraco.Core/Cache/IValueEditorCache.cs
index 790907c7500a..0061922927e6 100644
--- a/src/Umbraco.Core/Cache/IValueEditorCache.cs
+++ b/src/Umbraco.Core/Cache/IValueEditorCache.cs
@@ -3,9 +3,26 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Provides caching for instances associated with data types.
+///
+///
+/// This cache reduces the computational overhead of repeatedly creating value editors for
+/// the same data type and editor combinations during request processing.
+///
public interface IValueEditorCache
{
+ ///
+ /// Gets the value editor for the specified data editor and data type combination.
+ ///
+ /// The data editor.
+ /// The data type.
+ /// The cached or newly created .
public IDataValueEditor GetValueEditor(IDataEditor dataEditor, IDataType dataType);
+ ///
+ /// Clears the cached value editors for the specified data type identifiers.
+ ///
+ /// The data type identifiers to clear from the cache.
public void ClearCache(IEnumerable dataTypeIds);
}
diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs
index f140680b8c9d..5a61696e1de0 100644
--- a/src/Umbraco.Core/Cache/NoAppCache.cs
+++ b/src/Umbraco.Core/Cache/NoAppCache.cs
@@ -7,6 +7,12 @@ namespace Umbraco.Cms.Core.Cache;
///
public class NoAppCache : IAppPolicyCache, IRequestCache
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Protected to enforce singleton pattern via .
+ ///
protected NoAppCache()
{
}
@@ -74,12 +80,19 @@ public virtual void ClearByRegex(string regex)
{
}
+ ///
public bool Set(string key, object? value) => false;
+ ///
public bool Remove(string key) => false;
+ ///
+ /// Returns an enumerator that iterates through an empty collection.
+ ///
+ /// An enumerator for an empty collection.
public IEnumerator> GetEnumerator() =>
new Dictionary().GetEnumerator();
+ ///
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
diff --git a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs
index 2b662d4c2cde..4a347bba5747 100644
--- a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs
@@ -2,32 +2,55 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Implements with no caching behavior.
+///
+/// The type of the entity.
+/// The type of the entity identifier.
+///
+/// This policy bypasses all caching and directly delegates to the repository methods.
+/// Used when caching is not desired for a particular repository.
+///
public class NoCacheRepositoryCachePolicy : IRepositoryCachePolicy
where TEntity : class, IEntity
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
private NoCacheRepositoryCachePolicy()
{
}
+ ///
+ /// Gets the singleton instance of the no-cache policy.
+ ///
public static NoCacheRepositoryCachePolicy Instance { get; } = new();
+ ///
public TEntity? Get(TId? id, Func performGet, Func?> performGetAll) =>
performGet(id);
+ ///
public TEntity? GetCached(TId id) => null;
+ ///
public bool Exists(TId id, Func performExists, Func?> performGetAll) =>
performExists(id);
+ ///
public void Create(TEntity entity, Action persistNew) => persistNew(entity);
+ ///
public void Update(TEntity entity, Action persistUpdated) => persistUpdated(entity);
+ ///
public void Delete(TEntity entity, Action persistDeleted) => persistDeleted(entity);
+ ///
public TEntity[] GetAll(TId[]? ids, Func?> performGetAll) =>
performGetAll(ids)?.ToArray() ?? Array.Empty();
+ ///
public void ClearAll()
{
}
diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
index 4b9d237ea4c6..e6cd6a792171 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
@@ -330,10 +330,15 @@ private void ClearByPredicate(Func predicate)
}
}
+ ///
public void Dispose()
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
=> Dispose(true);
+ ///
+ /// Releases unmanaged and - optionally - managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
diff --git a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherBase.cs b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherBase.cs
index 0873d32cb853..acc6ea166143 100644
--- a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherBase.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherBase.cs
@@ -85,6 +85,9 @@ public virtual void Remove(int id) =>
///
protected AppCaches AppCaches { get; }
+ ///
+ /// Gets the event aggregator for publishing notifications.
+ ///
protected IEventAggregator EventAggregator { get; }
///
diff --git a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollection.cs b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollection.cs
index 301f6bbdaf1b..51f63d610d4f 100644
--- a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollection.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollection.cs
@@ -2,13 +2,28 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Represents a collection of instances.
+///
+///
+/// This collection provides access to all registered cache refreshers, allowing lookup by unique identifier.
+///
public class CacheRefresherCollection : BuilderCollectionBase
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A factory function that returns the cache refresher instances.
public CacheRefresherCollection(Func> items)
: base(items)
{
}
+ ///
+ /// Gets the cache refresher with the specified unique identifier.
+ ///
+ /// The unique identifier of the cache refresher.
+ /// The cache refresher with the specified identifier, or null if not found.
public ICacheRefresher? this[Guid id]
=> this.FirstOrDefault(x => x.RefresherUniqueId == id);
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollectionBuilder.cs b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollectionBuilder.cs
index 79b44ab53d14..3cf7abd3c0eb 100644
--- a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollectionBuilder.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherCollectionBuilder.cs
@@ -2,8 +2,15 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Builds a from registered instances.
+///
+///
+/// Use this builder to register custom cache refreshers during application composition.
+///
public class CacheRefresherCollectionBuilder : LazyCollectionBuilderBase
{
+ ///
protected override CacheRefresherCollectionBuilder This => this;
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherNotificationFactory.cs b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherNotificationFactory.cs
index 40bab16b12dd..4a12a3d2ea16 100644
--- a/src/Umbraco.Core/Cache/Refreshers/CacheRefresherNotificationFactory.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/CacheRefresherNotificationFactory.cs
@@ -12,6 +12,10 @@ public sealed class CacheRefresherNotificationFactory : ICacheRefresherNotificat
{
private readonly IServiceProvider _serviceProvider;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The service provider.
public CacheRefresherNotificationFactory(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
///
diff --git a/src/Umbraco.Core/Cache/Refreshers/ICacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/ICacheRefresher.cs
index dba0cd3b3fa4..b570873901a1 100644
--- a/src/Umbraco.Core/Cache/Refreshers/ICacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/ICacheRefresher.cs
@@ -3,35 +3,68 @@
namespace Umbraco.Cms.Core.Cache;
///
-/// The IcacheRefresher Interface is used for load balancing.
+/// Defines a cache refresher used for distributed cache invalidation in load-balanced environments.
///
+///
+/// Cache refreshers are responsible for invalidating or refreshing cached data across all servers
+/// in a load-balanced cluster when data changes occur.
+///
public interface ICacheRefresher : IDiscoverable
{
+ ///
+ /// Gets the unique identifier for this cache refresher.
+ ///
Guid RefresherUniqueId { get; }
+ ///
+ /// Gets the name of this cache refresher.
+ ///
string Name { get; }
+ ///
+ /// Refreshes all cached items managed by this refresher.
+ ///
void RefreshAll();
+ ///
+ /// Refreshes a specific cached item by its integer identifier.
+ ///
+ /// The identifier of the item to refresh.
void Refresh(int id);
+ ///
+ /// Removes a specific cached item by its integer identifier.
+ ///
+ /// The identifier of the item to remove.
void Remove(int id);
+ ///
+ /// Refreshes a specific cached item by its GUID identifier.
+ ///
+ /// The GUID of the item to refresh.
void Refresh(Guid id);
}
///
-/// Strongly type cache refresher that is able to refresh cache of real instances of objects as well as IDs
+/// Defines a strongly typed cache refresher that can refresh cache using object instances.
///
-///
+/// The type of entity being cached.
///
-/// This is much better for performance when we're not running in a load balanced environment so we can refresh the
-/// cache
-/// against a already resolved object instead of looking the object back up by id.
+/// This interface provides better performance in non-load-balanced environments by allowing
+/// cache refresh operations on already-resolved object instances, avoiding the need to
+/// re-lookup objects by their identifiers.
///
public interface ICacheRefresher : ICacheRefresher
{
+ ///
+ /// Refreshes the cache for the specified instance.
+ ///
+ /// The instance to refresh in the cache.
void Refresh(T instance);
+ ///
+ /// Removes the specified instance from the cache.
+ ///
+ /// The instance to remove from the cache.
void Remove(T instance);
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/ApplicationCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/ApplicationCacheRefresher.cs
index 11ddd8a18349..7b43a087b0c8 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/ApplicationCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/ApplicationCacheRefresher.cs
@@ -3,31 +3,48 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for application section (tree) caches.
+///
public sealed class ApplicationCacheRefresher : CacheRefresherBase
{
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("B15F34A1-BC1D-4F8B-8369-3222728AB4C8");
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The event aggregator.
+ /// The notification factory.
public ApplicationCacheRefresher(AppCaches appCaches, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, eventAggregator, factory)
{
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Application Cache Refresher";
+ ///
public override void RefreshAll()
{
AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationsCacheKey);
base.RefreshAll();
}
+ ///
public override void Refresh(int id)
{
Remove(id);
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationsCacheKey);
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
index 831520c4a951..5f68a46df7e6 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/ContentTypeCacheRefresher.cs
@@ -11,6 +11,9 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for content type, media type, and member type caches.
+///
public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase
{
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
@@ -21,6 +24,20 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The content type common repository.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The published model factory.
+ /// The published content type factory.
+ /// The document cache service.
+ /// The published content type cache.
+ /// The media cache service.
public ContentTypeCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -46,8 +63,17 @@ public ContentTypeCacheRefresher(
#region Json
+ ///
+ /// Represents the JSON payload for content type cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type name of the content type.
+ /// The identifier of the content type.
+ /// The types of changes that occurred.
public JsonPayload(string itemType, int id, ContentTypeChangeTypes changeTypes)
{
ItemType = itemType;
@@ -55,10 +81,19 @@ public JsonPayload(string itemType, int id, ContentTypeChangeTypes changeTypes)
ChangeTypes = changeTypes;
}
+ ///
+ /// Gets the type name of the content type (e.g., IContentType, IMediaType, IMemberType).
+ ///
public string ItemType { get; }
+ ///
+ /// Gets the identifier of the content type.
+ ///
public int Id { get; }
+ ///
+ /// Gets the types of changes that occurred.
+ ///
public ContentTypeChangeTypes ChangeTypes { get; }
}
@@ -66,16 +101,22 @@ public JsonPayload(string itemType, int id, ContentTypeChangeTypes changeTypes)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("6902E22C-9C10-483C-91F3-66B7CAE9E2F5");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Content Type Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
// TODO: refactor
@@ -127,6 +168,7 @@ public override void RefreshInternal(JsonPayload[] payloads)
base.RefreshInternal(payloads);
}
+ ///
public override void Refresh(JsonPayload[] payloads)
{
_publishedContentTypeCache.ClearContentTypes(payloads.Select(x => x.Id));
@@ -144,12 +186,16 @@ public override void Refresh(JsonPayload[] payloads)
base.Refresh(payloads);
}
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
index 364536b85239..cf939ad88186 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/DataTypeCacheRefresher.cs
@@ -12,6 +12,9 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for data type caches.
+///
public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase
{
private readonly IIdKeyMap _idKeyMap;
@@ -22,6 +25,20 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The published model factory.
+ /// The published content type factory.
+ /// The published content type cache.
+ /// The document cache service.
+ /// The media cache service.
+ /// The content type common repository.
public DataTypeCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -45,6 +62,19 @@ public DataTypeCacheRefresher(
_contentTypeCommonRepository = contentTypeCommonRepository;
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The published model factory.
+ /// The published content type factory.
+ /// The published content type cache.
+ /// The document cache service.
+ /// The media cache service.
[Obsolete("Use the non-obsolete constructor instead. Scheduled for removal in V18.")]
public DataTypeCacheRefresher(
AppCaches appCaches,
@@ -74,8 +104,17 @@ public DataTypeCacheRefresher(
#region Json
+ ///
+ /// Represents the JSON payload for data type cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the data type.
+ /// The unique key of the data type.
+ /// Whether the data type was removed.
public JsonPayload(int id, Guid key, bool removed)
{
Id = id;
@@ -83,10 +122,19 @@ public JsonPayload(int id, Guid key, bool removed)
Removed = removed;
}
+ ///
+ /// Gets the identifier of the data type.
+ ///
public int Id { get; }
+ ///
+ /// Gets the unique key of the data type.
+ ///
public Guid Key { get; }
+ ///
+ /// Gets a value indicating whether the data type was removed.
+ ///
public bool Removed { get; }
}
@@ -94,16 +142,22 @@ public JsonPayload(int id, Guid key, bool removed)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Data Type Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
// we need to clear the ContentType runtime cache since that is what caches the
@@ -134,6 +188,7 @@ public override void RefreshInternal(JsonPayload[] payloads)
base.RefreshInternal(payloads);
}
+ ///
public override void Refresh(JsonPayload[] payloads)
{
List removedContentTypes = new();
@@ -162,12 +217,17 @@ public override void Refresh(JsonPayload[] payloads)
// these events should never trigger
// everything should be PAYLOAD/JSON
+
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/DictionaryCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/DictionaryCacheRefresher.cs
index c10640986caa..3d010b9541db 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/DictionaryCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/DictionaryCacheRefresher.cs
@@ -4,25 +4,41 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for dictionary item caches.
+///
public sealed class DictionaryCacheRefresher : CacheRefresherBase
{
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("D1D7E227-F817-4816-BFE9-6C39B6152884");
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The event aggregator.
+ /// The notification factory.
public DictionaryCacheRefresher(AppCaches appCaches, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, eventAggregator, factory)
{
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Dictionary Cache Refresher";
+ ///
public override void Refresh(int id)
{
ClearAllIsolatedCacheByEntityType();
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
ClearAllIsolatedCacheByEntityType();
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
index 55dd2444a364..970b31d2cfa5 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/DomainCacheRefresher.cs
@@ -7,10 +7,21 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for domain caches.
+///
public sealed class DomainCacheRefresher : PayloadCacheRefresherBase
{
private readonly IDomainCacheService _domainCacheService;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The domain cache service.
public DomainCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -24,16 +35,30 @@ public DomainCacheRefresher(
#region Json
+ ///
+ /// Represents the JSON payload for domain cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the domain.
+ /// The type of change that occurred.
public JsonPayload(int id, DomainChangeTypes changeType)
{
Id = id;
ChangeType = changeType;
}
+ ///
+ /// Gets the identifier of the domain.
+ ///
public int Id { get; }
+ ///
+ /// Gets the type of change that occurred.
+ ///
public DomainChangeTypes ChangeType { get; }
}
@@ -41,16 +66,22 @@ public JsonPayload(int id, DomainChangeTypes changeType)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("11290A79-4B57-4C99-AD72-7748A3CF38AF");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Domain Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
ClearAllIsolatedCacheByEntityType();
@@ -67,12 +98,17 @@ public override void RefreshInternal(JsonPayload[] payloads)
// these events should never trigger
// everything should be PAYLOAD/JSON
+
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/LanguageCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/LanguageCacheRefresher.cs
index 335065774860..65023c39a144 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/LanguageCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/LanguageCacheRefresher.cs
@@ -8,11 +8,22 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for language caches.
+///
public sealed class LanguageCacheRefresher : PayloadCacheRefresherBase
{
private readonly IDomainCacheService _domainCacheService;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The event aggregator.
+ /// The domain cache service.
+ /// The cache refresher notification factory.
public LanguageCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -43,8 +54,14 @@ private void RefreshDomains()
#region Json
+ ///
+ /// Represents the JSON payload for language cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Defines the types of changes that can occur to a language.
+ ///
public enum LanguageChangeType
{
///
@@ -68,6 +85,12 @@ public enum LanguageChangeType
ChangeCulture = 3,
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the language.
+ /// The ISO code of the language.
+ /// The type of change that occurred.
public JsonPayload(int id, string isoCode, LanguageChangeType changeType)
{
Id = id;
@@ -75,10 +98,19 @@ public JsonPayload(int id, string isoCode, LanguageChangeType changeType)
ChangeType = changeType;
}
+ ///
+ /// Gets the identifier of the language.
+ ///
public int Id { get; }
+ ///
+ /// Gets the ISO code of the language.
+ ///
public string IsoCode { get; }
+ ///
+ /// Gets the type of change that occurred.
+ ///
public LanguageChangeType ChangeType { get; }
}
@@ -86,16 +118,22 @@ public JsonPayload(int id, string isoCode, LanguageChangeType changeType)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("3E0F95D8-0BE5-44B8-8394-2B8750B62654");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Language Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
// Languages has no concept of "published" languages, so all caches are "internal"
@@ -142,12 +180,17 @@ public override void RefreshInternal(JsonPayload[] payloads)
// these events should never trigger
// everything should be PAYLOAD/JSON
+
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs
index f54c78de1b7a..00f78a5aea0b 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs
@@ -13,6 +13,9 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for media caches.
+///
public sealed class MediaCacheRefresher : PayloadCacheRefresherBase
{
private readonly IIdKeyMap _idKeyMap;
@@ -22,6 +25,19 @@ public sealed class MediaCacheRefresher : PayloadCacheRefresherBase
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The media navigation query service.
+ /// The media navigation management service.
+ /// The media service.
+ /// The media cache service.
+ /// The cache manager.
public MediaCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -47,14 +63,27 @@ public MediaCacheRefresher(
#region Indirect
+ ///
+ /// Refreshes media type caches by clearing all cached media.
+ ///
+ /// The application caches.
public static void RefreshMediaTypes(AppCaches appCaches) => appCaches.IsolatedCaches.ClearCache();
#endregion
#region Json
+ ///
+ /// Represents the JSON payload for media cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the media item.
+ /// The unique key of the media item.
+ /// The types of changes that occurred.
public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
{
Id = id;
@@ -62,10 +91,19 @@ public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
ChangeTypes = changeTypes;
}
+ ///
+ /// Gets the identifier of the media item.
+ ///
public int Id { get; }
+ ///
+ /// Gets the unique key of the media item.
+ ///
public Guid? Key { get; }
+ ///
+ /// Gets the types of changes that occurred.
+ ///
public TreeChangeTypes ChangeTypes { get; }
}
@@ -73,16 +111,22 @@ public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("B29286DD-2D40-4DDB-B325-681226589FEC");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Media Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
// actions that always need to happen
@@ -125,6 +169,7 @@ public override void RefreshInternal(JsonPayload[] payloads)
base.RefreshInternal(payloads);
}
+ ///
public override void Refresh(JsonPayload[]? payloads)
{
if (payloads is null)
@@ -284,12 +329,17 @@ private void HandleNavigationForSingleMedia(IMedia media)
// these events should never trigger
// everything should be JSON
+
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs
index 2a7b449aaf12..a9baafe0953d 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberCacheRefresher.cs
@@ -10,13 +10,27 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for member caches.
+///
public sealed class MemberCacheRefresher : PayloadCacheRefresherBase
{
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("E285DF34-ACDC-4226-AE32-C0CB5CF388DA");
private readonly IIdKeyMap _idKeyMap;
private readonly IMemberPartialViewCacheInvalidator _memberPartialViewCacheInvalidator;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
[Obsolete("Use the non obsoleted contructor instead. Planned for removal in V18")]
public MemberCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IIdKeyMap idKeyMap, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: this(
@@ -29,6 +43,15 @@ public MemberCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IId
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The ID-key mapping service.
+ /// The event aggregator.
+ /// The cache refresher notification factory.
+ /// The member partial view cache invalidator.
public MemberCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -44,13 +67,25 @@ public MemberCacheRefresher(
#region Indirect
+ ///
+ /// Refreshes member type caches by clearing all cached members.
+ ///
+ /// The application caches.
public static void RefreshMemberTypes(AppCaches appCaches) => appCaches.IsolatedCaches.ClearCache();
#endregion
+ ///
+ /// Represents the JSON payload for member cache refresh operations.
+ ///
public class JsonPayload
{
- // [JsonConstructor]
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the member.
+ /// The username of the member.
+ /// Whether the member was removed.
public JsonPayload(int id, string? username, bool removed)
{
Id = id;
@@ -58,31 +93,48 @@ public JsonPayload(int id, string? username, bool removed)
Removed = removed;
}
+ ///
+ /// Gets the identifier of the member.
+ ///
public int Id { get; }
+ ///
+ /// Gets the username of the member.
+ ///
public string? Username { get; }
+ ///
+ /// Gets or sets the previous username of the member, if changed.
+ ///
public string? PreviousUsername { get; set; }
+ ///
+ /// Gets a value indicating whether the member was removed.
+ ///
public bool Removed { get; }
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Member Cache Refresher";
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
ClearCache(payloads);
base.RefreshInternal(payloads);
}
+ ///
public override void Refresh(int id)
{
ClearCache(new JsonPayload(id, null, false));
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
ClearCache(new JsonPayload(id, null, false));
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberGroupCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberGroupCacheRefresher.cs
index 0d5eaf0010c9..bca0df960493 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/MemberGroupCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/MemberGroupCacheRefresher.cs
@@ -5,8 +5,18 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for member group caches.
+///
public sealed class MemberGroupCacheRefresher : PayloadCacheRefresherBase
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The event aggregator.
+ /// The notification factory.
public MemberGroupCacheRefresher(AppCaches appCaches, IJsonSerializer jsonSerializer, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, jsonSerializer, eventAggregator, factory)
{
@@ -14,16 +24,30 @@ public MemberGroupCacheRefresher(AppCaches appCaches, IJsonSerializer jsonSerial
#region Json
+ ///
+ /// Represents the JSON payload for member group cache refresh operations.
+ ///
public class JsonPayload
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identifier of the member group.
+ /// The name of the member group.
public JsonPayload(int id, string name)
{
Id = id;
Name = name;
}
+ ///
+ /// Gets the name of the member group.
+ ///
public string Name { get; }
+ ///
+ /// Gets the identifier of the member group.
+ ///
public int Id { get; }
}
@@ -31,28 +55,36 @@ public JsonPayload(int id, string name)
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("187F236B-BD21-4C85-8A7C-29FBA3D6C00C");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Member Group Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
ClearCache();
base.RefreshInternal(payloads);
}
+ ///
public override void Refresh(int id)
{
ClearCache();
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
ClearCache();
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/PublicAccessCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/PublicAccessCacheRefresher.cs
index 9124d7350ec3..8dd82beb3df5 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/PublicAccessCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/PublicAccessCacheRefresher.cs
@@ -4,43 +4,61 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for public access entry caches.
+///
public sealed class PublicAccessCacheRefresher : CacheRefresherBase
{
#region Define
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("1DB08769-B104-4F8B-850E-169CAC1DF2EC");
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The event aggregator.
+ /// The notification factory.
public PublicAccessCacheRefresher(AppCaches appCaches, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, eventAggregator, factory)
{
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Public Access Cache Refresher";
#endregion
#region Refresher
+ ///
public override void Refresh(Guid id)
{
ClearAllIsolatedCacheByEntityType();
base.Refresh(id);
}
+ ///
public override void Refresh(int id)
{
ClearAllIsolatedCacheByEntityType();
base.Refresh(id);
}
+ ///
public override void RefreshAll()
{
ClearAllIsolatedCacheByEntityType();
base.RefreshAll();
}
+ ///
public override void Remove(int id)
{
ClearAllIsolatedCacheByEntityType();
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/RelationTypeCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/RelationTypeCacheRefresher.cs
index 8da3cd5be0a4..e0e197ecd619 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/RelationTypeCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/RelationTypeCacheRefresher.cs
@@ -5,25 +5,41 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for relation type caches.
+///
public sealed class RelationTypeCacheRefresher : CacheRefresherBase
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The event aggregator.
+ /// The notification factory.
public RelationTypeCacheRefresher(AppCaches appCaches, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, eventAggregator, factory)
{
}
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("D8375ABA-4FB3-4F86-B505-92FBA1B6F7C9");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Relation Type Cache Refresher";
+ ///
public override void RefreshAll()
{
ClearAllIsolatedCacheByEntityType();
base.RefreshAll();
}
+ ///
public override void Refresh(int id)
{
Attempt cache = AppCaches.IsolatedCaches.Get();
@@ -35,9 +51,10 @@ public override void Refresh(int id)
base.Refresh(id);
}
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
- // base.Refresh(id);
+ ///
public override void Remove(int id)
{
Attempt cache = AppCaches.IsolatedCaches.Get();
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/TemplateCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/TemplateCacheRefresher.cs
index 221ad7c8363a..daa44b599fa9 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/TemplateCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/TemplateCacheRefresher.cs
@@ -6,13 +6,27 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for template caches.
+///
public sealed class TemplateCacheRefresher : CacheRefresherBase
{
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("DD12B6A0-14B9-46e8-8800-C154F74047C8");
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
private readonly IIdKeyMap _idKeyMap;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The ID/key map service.
+ /// The content type common repository.
+ /// The event aggregator.
+ /// The notification factory.
public TemplateCacheRefresher(
AppCaches appCaches,
IIdKeyMap idKeyMap,
@@ -25,16 +39,20 @@ public TemplateCacheRefresher(
_contentTypeCommonRepository = contentTypeCommonRepository;
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "Template Cache Refresher";
+ ///
public override void Refresh(int id)
{
RemoveFromCache(id);
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
RemoveFromCache(id);
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/UserCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/UserCacheRefresher.cs
index 2a142df1f67d..ced590db514d 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/UserCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/UserCacheRefresher.cs
@@ -6,32 +6,58 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for user caches.
+///
public sealed class UserCacheRefresher : PayloadCacheRefresherBase
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The event aggregator.
+ /// The notification factory.
public UserCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, serializer, eventAggregator, factory)
{
}
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("E057AF6D-2EE6-41F4-8045-3694010F0AA6");
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "User Cache Refresher";
+ ///
+ /// Represents the JSON payload for user cache refresh operations.
+ ///
public record JsonPayload
{
+ ///
+ /// Gets the identifier of the user.
+ ///
public int Id { get; init; }
+ ///
+ /// Gets the unique key of the user.
+ ///
public Guid Key { get; init; }
}
+ ///
public override void RefreshAll()
{
ClearAllIsolatedCacheByEntityType();
base.RefreshAll();
}
+ ///
public override void RefreshInternal(JsonPayload[] payloads)
{
ClearCache(payloads);
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/UserGroupCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/UserGroupCacheRefresher.cs
index ccf004a8d7d0..d3734336ec5e 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/UserGroupCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/UserGroupCacheRefresher.cs
@@ -15,21 +15,33 @@ public sealed class UserGroupCacheRefresher : CacheRefresherBase
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("45178038-B232-4FE8-AA1A-F2B949C44762");
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The event aggregator.
+ /// The notification factory.
public UserGroupCacheRefresher(AppCaches appCaches, IEventAggregator eventAggregator, ICacheRefresherNotificationFactory factory)
: base(appCaches, eventAggregator, factory)
{
}
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "User Group Cache Refresher";
#endregion
#region Refresher
+ ///
public override void RefreshAll()
{
ClearAllIsolatedCacheByEntityType();
@@ -45,12 +57,14 @@ public override void RefreshAll()
base.RefreshAll();
}
+ ///
public override void Refresh(int id)
{
Remove(id);
base.Refresh(id);
}
+ ///
public override void Remove(int id)
{
Attempt userGroupCache = AppCaches.IsolatedCaches.Get();
diff --git a/src/Umbraco.Core/Cache/Refreshers/Implement/ValueEditorCacheRefresher.cs b/src/Umbraco.Core/Cache/Refreshers/Implement/ValueEditorCacheRefresher.cs
index 2aed28d48897..be417bb4139a 100644
--- a/src/Umbraco.Core/Cache/Refreshers/Implement/ValueEditorCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/Implement/ValueEditorCacheRefresher.cs
@@ -4,12 +4,26 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Cache refresher for value editor caches.
+///
public sealed class ValueEditorCacheRefresher : PayloadCacheRefresherBase
{
+ ///
+ /// The unique identifier for this cache refresher.
+ ///
public static readonly Guid UniqueId = Guid.Parse("D28A1DBB-2308-4918-9A92-2F8689B6CBFE");
private readonly IValueEditorCache _valueEditorCache;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application caches.
+ /// The JSON serializer.
+ /// The event aggregator.
+ /// The notification factory.
+ /// The value editor cache.
public ValueEditorCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
@@ -19,10 +33,13 @@ public ValueEditorCacheRefresher(
: base(appCaches, serializer, eventAggregator, factory) =>
_valueEditorCache = valueEditorCache;
+ ///
public override Guid RefresherUniqueId => UniqueId;
+ ///
public override string Name => "ValueEditorCacheRefresher";
+ ///
public override void RefreshInternal(DataTypeCacheRefresher.JsonPayload[] payloads)
{
IEnumerable ids = payloads.Select(x => x.Id);
@@ -32,11 +49,16 @@ public override void RefreshInternal(DataTypeCacheRefresher.JsonPayload[] payloa
// these events should never trigger
// everything should be PAYLOAD/JSON
+
+ ///
public override void RefreshAll() => throw new NotSupportedException();
+ ///
public override void Refresh(int id) => throw new NotSupportedException();
+ ///
public override void Refresh(Guid id) => throw new NotSupportedException();
+ ///
public override void Remove(int id) => throw new NotSupportedException();
}
diff --git a/src/Umbraco.Core/Cache/Refreshers/JsonCacheRefresherBase.cs b/src/Umbraco.Core/Cache/Refreshers/JsonCacheRefresherBase.cs
index 52f0d7439c8a..b2d764b0ba26 100644
--- a/src/Umbraco.Core/Cache/Refreshers/JsonCacheRefresherBase.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/JsonCacheRefresherBase.cs
@@ -24,6 +24,9 @@ protected JsonCacheRefresherBase(
: base(appCaches, eventAggregator, factory) =>
JsonSerializer = jsonSerializer;
+ ///
+ /// Gets the JSON serializer.
+ ///
protected IJsonSerializer JsonSerializer { get; }
///
@@ -47,6 +50,11 @@ public virtual void RefreshInternal(string json)
/// The deserialized object payload.
public TJsonPayload[]? Deserialize(string json) => JsonSerializer.Deserialize(json);
+ ///
+ /// Serializes the specified payloads to a JSON string.
+ ///
+ /// The payloads to serialize.
+ /// The JSON string representation of the payloads.
public string Serialize(params TJsonPayload[] jsonPayloads) => JsonSerializer.Serialize(jsonPayloads);
#endregion
diff --git a/src/Umbraco.Core/Cache/Refreshers/PayloadCacheRefresherBase.cs b/src/Umbraco.Core/Cache/Refreshers/PayloadCacheRefresherBase.cs
index 8fc8e1e4711b..a09a9f48ae20 100644
--- a/src/Umbraco.Core/Cache/Refreshers/PayloadCacheRefresherBase.cs
+++ b/src/Umbraco.Core/Cache/Refreshers/PayloadCacheRefresherBase.cs
@@ -30,6 +30,7 @@ protected PayloadCacheRefresherBase(AppCaches appCaches, IJsonSerializer seriali
#region Refresher
+ ///
public override void Refresh(string json)
{
TPayload[]? payload = Deserialize(json);
@@ -56,6 +57,10 @@ public override void RefreshInternal(string json)
public virtual void Refresh(TPayload[] payloads) =>
OnCacheUpdated(NotificationFactory.Create(payloads, MessageType.RefreshByPayload));
+ ///
+ /// Performs internal cache refresh operations for the specified payloads.
+ ///
+ /// The payloads to process.
public virtual void RefreshInternal(TPayload[] payloads)
{
}
diff --git a/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs b/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs
index 09269f92e15f..6f400259cb37 100644
--- a/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs
+++ b/src/Umbraco.Core/Cache/RepositoryCacheVersionService.cs
@@ -1,4 +1,4 @@
-using System.Collections.Concurrent;
+using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
@@ -15,6 +15,13 @@ internal class RepositoryCacheVersionService : IRepositoryCacheVersionService
private readonly IRepositoryCacheVersionAccessor _repositoryCacheVersionAccessor;
private readonly ConcurrentDictionary _cacheVersions = new();
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The scope provider.
+ /// The repository cache version repository.
+ /// The logger.
+ /// The repository cache version accessor.
public RepositoryCacheVersionService(
ICoreScopeProvider scopeProvider,
IRepositoryCacheVersionRepository repositoryCacheVersionRepository,
@@ -116,6 +123,11 @@ public async Task SetCachesSyncedAsync()
scope.Complete();
}
+ ///
+ /// Gets the cache key for the specified entity type.
+ ///
+ /// The entity type.
+ /// The cache key for the entity type.
internal string GetCacheKey()
where TEntity : class =>
typeof(TEntity).FullName ?? typeof(TEntity).Name;
diff --git a/src/Umbraco.Core/Cache/SafeLazy.cs b/src/Umbraco.Core/Cache/SafeLazy.cs
index 40512ece67ac..f75864227579 100644
--- a/src/Umbraco.Core/Cache/SafeLazy.cs
+++ b/src/Umbraco.Core/Cache/SafeLazy.cs
@@ -2,11 +2,25 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Provides methods for creating and working with lazy values that safely handle exceptions.
+///
+///
+/// Safe lazy values capture exceptions during evaluation and return them as null values
+/// instead of re-throwing, preventing cache corruption from failed evaluations.
+///
public static class SafeLazy
{
- // an object that represent a value that has not been created yet
+ ///
+ /// An object that represents a value that has not been created yet.
+ ///
internal static readonly object ValueNotCreated = new();
+ ///
+ /// Creates a safe lazy that catches exceptions during evaluation.
+ ///
+ /// The factory function to create the cached item.
+ /// A lazy value that wraps exceptions in an instead of throwing.
public static Lazy GetSafeLazy(Func getCacheItem) =>
// try to generate the value and if it fails,
@@ -25,6 +39,12 @@ public static class SafeLazy
}
});
+ ///
+ /// Gets the value from a safe lazy, returning null for exceptions.
+ ///
+ /// The lazy value to evaluate.
+ /// If true , only returns the value if already created; otherwise returns .
+ /// The lazy value, if not yet created and is true , or null if an exception occurred.
public static object? GetSafeLazyValue(Lazy? lazy, bool onlyIfValueIsCreated = false)
{
// if onlyIfValueIsCreated, do not trigger value creation
@@ -55,10 +75,24 @@ public static class SafeLazy
}
}
+ ///
+ /// Holds an exception that occurred during lazy value evaluation.
+ ///
+ ///
+ /// Used to store exceptions in the cache without re-throwing them during normal access,
+ /// allowing the exception to be thrown once when the value is actually requested.
+ ///
public class ExceptionHolder
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The captured exception dispatch info.
public ExceptionHolder(ExceptionDispatchInfo e) => Exception = e;
+ ///
+ /// Gets the captured exception dispatch info.
+ ///
public ExceptionDispatchInfo Exception { get; }
}
}
diff --git a/src/Umbraco.Core/Cache/ValueEditorCache.cs b/src/Umbraco.Core/Cache/ValueEditorCache.cs
index e1ec12e5ef08..bcb6cf43eec7 100644
--- a/src/Umbraco.Core/Cache/ValueEditorCache.cs
+++ b/src/Umbraco.Core/Cache/ValueEditorCache.cs
@@ -3,17 +3,28 @@
namespace Umbraco.Cms.Core.Cache;
+///
+/// Implements to cache instances.
+///
+///
+/// This cache stores value editors keyed by data editor alias and data type ID to avoid
+/// repeatedly creating value editor instances during request processing.
+///
public class ValueEditorCache : IValueEditorCache
{
private readonly Lock _dictionaryLocker;
private readonly Dictionary> _valueEditorCache;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public ValueEditorCache()
{
_valueEditorCache = new Dictionary>();
_dictionaryLocker = new Lock();
}
+ ///
public IDataValueEditor GetValueEditor(IDataEditor editor, IDataType dataType)
{
// Lock just in case multiple threads uses the cache at the same time.
@@ -41,6 +52,7 @@ public IDataValueEditor GetValueEditor(IDataEditor editor, IDataType dataType)
}
}
+ ///
public void ClearCache(IEnumerable dataTypeIds)
{
lock (_dictionaryLocker)
diff --git a/src/Umbraco.Core/CacheSyncService.cs b/src/Umbraco.Core/CacheSyncService.cs
index c093b6f17921..98dd7e3b7730 100644
--- a/src/Umbraco.Core/CacheSyncService.cs
+++ b/src/Umbraco.Core/CacheSyncService.cs
@@ -4,12 +4,21 @@
namespace Umbraco.Cms.Core;
+///
+/// Default implementation of that synchronizes caches across servers.
+///
public class CacheSyncService : ICacheSyncService
{
private readonly IMachineInfoFactory _machineInfoFactory;
private readonly CacheRefresherCollection _cacheRefreshers;
private readonly ICacheInstructionService _cacheInstructionService;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The factory for getting machine information.
+ /// The collection of cache refreshers.
+ /// The service for processing cache instructions.
public CacheSyncService(
IMachineInfoFactory machineInfoFactory,
CacheRefresherCollection cacheRefreshers,
diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
index 13ec38f892c7..a268fe17fb29 100644
--- a/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
+++ b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
@@ -1,20 +1,35 @@
namespace Umbraco.Cms.Core.CodeAnnotations;
///
-/// Attribute to associate a GUID string and Type with an UmbracoObjectType Enum value
+/// Attribute to associate a GUID string and Type with an UmbracoObjectType enum value.
///
[AttributeUsage(AttributeTargets.Field)]
public class UmbracoObjectTypeAttribute : Attribute
{
+ ///
+ /// Initializes a new instance of the class with a GUID string.
+ ///
+ /// The GUID string representing the object type identifier.
public UmbracoObjectTypeAttribute(string objectId) => ObjectId = new Guid(objectId);
+ ///
+ /// Initializes a new instance of the class with a GUID string and model type.
+ ///
+ /// The GUID string representing the object type identifier.
+ /// The CLR type associated with this object type.
public UmbracoObjectTypeAttribute(string objectId, Type modelType)
{
ObjectId = new Guid(objectId);
ModelType = modelType;
}
+ ///
+ /// Gets the unique identifier for the Umbraco object type.
+ ///
public Guid ObjectId { get; }
+ ///
+ /// Gets the CLR type associated with this object type, if specified.
+ ///
public Type? ModelType { get; }
}
diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs
index 90df3185c677..5d88815db911 100644
--- a/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs
+++ b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs
@@ -1,9 +1,22 @@
namespace Umbraco.Cms.Core.CodeAnnotations;
+///
+/// Attribute to associate a UDI (Umbraco Document Identifier) type string with an enum value.
+///
+///
+/// UDI types are string identifiers used in the Umbraco unified identifier system.
+///
[AttributeUsage(AttributeTargets.Field)]
public class UmbracoUdiTypeAttribute : Attribute
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The UDI type string.
public UmbracoUdiTypeAttribute(string udiType) => UdiType = udiType;
+ ///
+ /// Gets the UDI type string.
+ ///
public string UdiType { get; }
}
diff --git a/src/Umbraco.Core/Collections/CompositeIntStringKey.cs b/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
index abbde4f3f05b..f4c06ddb17fd 100644
--- a/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
+++ b/src/Umbraco.Core/Collections/CompositeIntStringKey.cs
@@ -27,18 +27,33 @@ public CompositeIntStringKey(int? key1, string? key2)
_key2 = key2?.ToLowerInvariant() ?? "NULL";
}
+ ///
+ /// Determines whether two instances are equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are equal; otherwise, false .
public static bool operator ==(CompositeIntStringKey key1, CompositeIntStringKey key2)
=> key1._key2 == key2._key2 && key1._key1 == key2._key1;
+ ///
+ /// Determines whether two instances are not equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are not equal; otherwise, false .
public static bool operator !=(CompositeIntStringKey key1, CompositeIntStringKey key2)
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
+ ///
public bool Equals(CompositeIntStringKey other)
=> _key2 == other._key2 && _key1 == other._key1;
+ ///
public override bool Equals(object? obj)
=> obj is CompositeIntStringKey other && _key2 == other._key2 && _key1 == other._key1;
+ ///
public override int GetHashCode()
=> (_key2.GetHashCode() * 31) + _key1;
}
diff --git a/src/Umbraco.Core/Collections/CompositeNStringNStringKey.cs b/src/Umbraco.Core/Collections/CompositeNStringNStringKey.cs
index 0b3ec1aa929b..5bf443789b6c 100644
--- a/src/Umbraco.Core/Collections/CompositeNStringNStringKey.cs
+++ b/src/Umbraco.Core/Collections/CompositeNStringNStringKey.cs
@@ -21,18 +21,33 @@ public CompositeNStringNStringKey(string? key1, string? key2)
_key2 = key2?.ToLowerInvariant() ?? "NULL";
}
+ ///
+ /// Determines whether two instances are equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are equal; otherwise, false .
public static bool operator ==(CompositeNStringNStringKey key1, CompositeNStringNStringKey key2)
=> key1._key2 == key2._key2 && key1._key1 == key2._key1;
+ ///
+ /// Determines whether two instances are not equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are not equal; otherwise, false .
public static bool operator !=(CompositeNStringNStringKey key1, CompositeNStringNStringKey key2)
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
+ ///
public bool Equals(CompositeNStringNStringKey other)
=> _key2 == other._key2 && _key1 == other._key1;
+ ///
public override bool Equals(object? obj)
=> obj is CompositeNStringNStringKey other && _key2 == other._key2 && _key1 == other._key1;
+ ///
public override int GetHashCode()
=> (_key2.GetHashCode() * 31) + _key1.GetHashCode();
}
diff --git a/src/Umbraco.Core/Collections/CompositeStringStringKey.cs b/src/Umbraco.Core/Collections/CompositeStringStringKey.cs
index 6fd25f6c1212..5efdfa7335a6 100644
--- a/src/Umbraco.Core/Collections/CompositeStringStringKey.cs
+++ b/src/Umbraco.Core/Collections/CompositeStringStringKey.cs
@@ -21,18 +21,33 @@ public CompositeStringStringKey(string? key1, string? key2)
_key2 = key2?.ToLowerInvariant() ?? throw new ArgumentNullException(nameof(key2));
}
+ ///
+ /// Determines whether two instances are equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are equal; otherwise, false .
public static bool operator ==(CompositeStringStringKey key1, CompositeStringStringKey key2)
=> key1._key2 == key2._key2 && key1._key1 == key2._key1;
+ ///
+ /// Determines whether two instances are not equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are not equal; otherwise, false .
public static bool operator !=(CompositeStringStringKey key1, CompositeStringStringKey key2)
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
+ ///
public bool Equals(CompositeStringStringKey other)
=> _key2 == other._key2 && _key1 == other._key1;
+ ///
public override bool Equals(object? obj)
=> obj is CompositeStringStringKey other && _key2 == other._key2 && _key1 == other._key1;
+ ///
public override int GetHashCode()
=> (_key2.GetHashCode() * 31) + _key1.GetHashCode();
}
diff --git a/src/Umbraco.Core/Collections/CompositeTypeTypeKey.cs b/src/Umbraco.Core/Collections/CompositeTypeTypeKey.cs
index ea9a5a496f42..7cf1a497b2ce 100644
--- a/src/Umbraco.Core/Collections/CompositeTypeTypeKey.cs
+++ b/src/Umbraco.Core/Collections/CompositeTypeTypeKey.cs
@@ -25,9 +25,21 @@ public CompositeTypeTypeKey(Type type1, Type type2)
///
public Type Type2 { get; }
+ ///
+ /// Determines whether two instances are equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are equal; otherwise, false .
public static bool operator ==(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2) =>
key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
+ ///
+ /// Determines whether two instances are not equal.
+ ///
+ /// The first key to compare.
+ /// The second key to compare.
+ /// true if the two keys are not equal; otherwise, false .
public static bool operator !=(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2) =>
key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
diff --git a/src/Umbraco.Core/Collections/ConcurrentHashSet.cs b/src/Umbraco.Core/Collections/ConcurrentHashSet.cs
index ee4f5b707e22..41954618597e 100644
--- a/src/Umbraco.Core/Collections/ConcurrentHashSet.cs
+++ b/src/Umbraco.Core/Collections/ConcurrentHashSet.cs
@@ -256,6 +256,10 @@ public void CopyTo(Array array, int index)
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
}
+ ///
+ /// Creates a thread-safe clone of the internal hash set.
+ ///
+ /// A new containing a copy of the elements.
private HashSet GetThreadSafeClone()
{
HashSet? clone = null;
@@ -275,6 +279,7 @@ private HashSet GetThreadSafeClone()
return clone;
}
+ ///
public void ExceptWith(IEnumerable other)
{
try
@@ -291,6 +296,7 @@ public void ExceptWith(IEnumerable other)
}
}
+ ///
public void IntersectWith(IEnumerable other)
{
try
@@ -307,6 +313,7 @@ public void IntersectWith(IEnumerable other)
}
}
+ ///
public bool IsProperSubsetOf(IEnumerable other)
{
try
@@ -323,6 +330,7 @@ public bool IsProperSubsetOf(IEnumerable other)
}
}
+ ///
public bool IsProperSupersetOf(IEnumerable other)
{
try
@@ -339,6 +347,7 @@ public bool IsProperSupersetOf(IEnumerable other)
}
}
+ ///
public bool IsSubsetOf(IEnumerable other)
{
try
@@ -355,6 +364,7 @@ public bool IsSubsetOf(IEnumerable other)
}
}
+ ///
public bool IsSupersetOf(IEnumerable other)
{
try
@@ -371,6 +381,7 @@ public bool IsSupersetOf(IEnumerable other)
}
}
+ ///
public bool Overlaps(IEnumerable other)
{
try
@@ -387,6 +398,7 @@ public bool Overlaps(IEnumerable other)
}
}
+ ///
public bool SetEquals(IEnumerable other)
{
try
@@ -403,6 +415,7 @@ public bool SetEquals(IEnumerable other)
}
}
+ ///
public void SymmetricExceptWith(IEnumerable other)
{
try
@@ -419,6 +432,7 @@ public void SymmetricExceptWith(IEnumerable other)
}
}
+ ///
public void UnionWith(IEnumerable other)
{
try
@@ -435,6 +449,7 @@ public void UnionWith(IEnumerable other)
}
}
+ ///
bool ISet.Add(T item)
{
try
diff --git a/src/Umbraco.Core/Collections/DeepCloneableList.cs b/src/Umbraco.Core/Collections/DeepCloneableList.cs
index 4f22ac094e0d..67512e3c1d70 100644
--- a/src/Umbraco.Core/Collections/DeepCloneableList.cs
+++ b/src/Umbraco.Core/Collections/DeepCloneableList.cs
@@ -12,21 +12,33 @@ public class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty
{
private readonly ListCloneBehavior _listCloneBehavior;
+ ///
+ /// Initializes a new instance of the class with the specified clone behavior.
+ ///
+ /// The clone behavior for the list.
public DeepCloneableList(ListCloneBehavior listCloneBehavior) => _listCloneBehavior = listCloneBehavior;
+ ///
+ /// Initializes a new instance of the class with a collection and the specified clone behavior.
+ ///
+ /// The collection whose elements are copied to the new list.
+ /// The clone behavior for the list.
public DeepCloneableList(IEnumerable collection, ListCloneBehavior listCloneBehavior)
: base(collection) =>
_listCloneBehavior = listCloneBehavior;
///
- /// Default behavior is CloneOnce
+ /// Initializes a new instance of the class with a collection.
///
- ///
+ /// The collection whose elements are copied to the new list.
+ /// Default behavior is .
public DeepCloneableList(IEnumerable collection)
: this(collection, ListCloneBehavior.CloneOnce)
{
}
+ ///
+ /// This event is not used by the list but is required by the interface.
public event PropertyChangedEventHandler? PropertyChanged; // noop
///
@@ -60,8 +72,10 @@ public object DeepClone()
#region IRememberBeingDirty
+ ///
public bool IsDirty() => this.OfType().Any(x => x.IsDirty());
+ ///
public bool WasDirty() => this.OfType().Any(x => x.WasDirty());
///
@@ -76,6 +90,7 @@ public object DeepClone()
/// Always return an empty enumerable, the list has no properties that can be dirty.
public IEnumerable GetDirtyProperties() => Enumerable.Empty();
+ ///
public void ResetDirtyProperties()
{
foreach (IRememberBeingDirty dc in this.OfType())
@@ -84,16 +99,19 @@ public void ResetDirtyProperties()
}
}
+ ///
public void DisableChangeTracking()
{
// noop
}
+ ///
public void EnableChangeTracking()
{
// noop
}
+ ///
public void ResetWereDirtyProperties()
{
foreach (IRememberBeingDirty dc in this.OfType())
@@ -102,6 +120,7 @@ public void ResetWereDirtyProperties()
}
}
+ ///
public void ResetDirtyProperties(bool rememberDirty)
{
foreach (IRememberBeingDirty dc in this.OfType())
diff --git a/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
index 3b0994c6147d..4d60f7c76c6e 100644
--- a/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
+++ b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
@@ -16,20 +16,34 @@ public class EventClearingObservableCollection : ObservableCollection
+ /// Initializes a new instance of the class.
+ ///
public EventClearingObservableCollection()
{
}
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified list.
+ ///
+ /// The list from which the elements are copied.
public EventClearingObservableCollection(List list)
: base(list)
{
}
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified collection.
+ ///
+ /// The collection from which the elements are copied.
public EventClearingObservableCollection(IEnumerable collection)
: base(collection)
{
}
+ ///
event NotifyCollectionChangedEventHandler? INotifyCollectionChanged.CollectionChanged
{
add => _changed += value;
@@ -41,6 +55,7 @@ event NotifyCollectionChangedEventHandler? INotifyCollectionChanged.CollectionCh
///
public void ClearCollectionChangedEvents() => _changed = null;
+ ///
public object DeepClone()
{
var clone = new EventClearingObservableCollection();
diff --git a/src/Umbraco.Core/Collections/ListCloneBehavior.cs b/src/Umbraco.Core/Collections/ListCloneBehavior.cs
index 4fc9edf3ae03..7ce6d107186c 100644
--- a/src/Umbraco.Core/Collections/ListCloneBehavior.cs
+++ b/src/Umbraco.Core/Collections/ListCloneBehavior.cs
@@ -1,5 +1,8 @@
namespace Umbraco.Cms.Core.Collections;
+///
+/// Specifies the behavior when deep cloning a .
+///
public enum ListCloneBehavior
{
///
diff --git a/src/Umbraco.Core/Collections/ObservableDictionary.cs b/src/Umbraco.Core/Collections/ObservableDictionary.cs
index 216b384e5f13..a08b21a30fd8 100644
--- a/src/Umbraco.Core/Collections/ObservableDictionary.cs
+++ b/src/Umbraco.Core/Collections/ObservableDictionary.cs
@@ -33,10 +33,21 @@ public ObservableDictionary(Func keySelector, IEqualityComparer(equalityComparer);
}
+ ///
+ /// Gets the dictionary mapping keys to their indices in the collection.
+ ///
protected Dictionary Indecies { get; }
+ ///
+ /// Gets the function used to extract a key from a value.
+ ///
protected Func KeySelector { get; }
+ ///
+ /// Removes the element with the specified key from the dictionary.
+ ///
+ /// The key of the element to remove.
+ /// true if the element is successfully found and removed; otherwise, false .
public bool Remove(TKey key)
{
if (!Indecies.TryGetValue(key, out int index))
@@ -48,12 +59,14 @@ public bool Remove(TKey key)
return true;
}
+ ///
event NotifyCollectionChangedEventHandler? INotifyCollectionChanged.CollectionChanged
{
add => _changed += value;
remove => _changed -= value;
}
+ ///
public bool ContainsKey(TKey key) => Indecies.ContainsKey(key);
///
@@ -112,6 +125,11 @@ public bool Replace(TKey key, TValue value)
return true;
}
+ ///
+ /// Replaces all elements in the dictionary with the specified values.
+ ///
+ /// The values to replace the current elements with.
+ /// Thrown when is null .
public void ReplaceAll(IEnumerable values)
{
if (values == null)
@@ -150,6 +168,7 @@ public void ChangeKey(TKey currentKey, TKey newKey)
#region Protected Methods
+ ///
protected override void InsertItem(int index, TValue item)
{
TKey key = KeySelector(item);
@@ -170,12 +189,14 @@ protected override void InsertItem(int index, TValue item)
Indecies[key] = index;
}
+ ///
protected override void ClearItems()
{
base.ClearItems();
Indecies.Clear();
}
+ ///
protected override void RemoveItem(int index)
{
TValue item = this[index];
@@ -195,6 +216,7 @@ protected override void RemoveItem(int index)
#region IDictionary and IReadOnlyDictionary implementation
+ ///
public bool TryGetValue(TKey key, out TValue val)
{
if (Indecies.TryGetValue(key, out var index))
@@ -217,13 +239,16 @@ public bool TryGetValue(TKey key, out TValue val)
///
public IEnumerable Values => Items;
+ ///
ICollection IDictionary.Keys => Indecies.Keys;
- // this will never be used
+ ///
ICollection IDictionary.Values => Values.ToList();
+ ///
bool ICollection>.IsReadOnly => false;
+ ///
IEnumerator> IEnumerable>.GetEnumerator()
{
foreach (TValue i in Values)
@@ -233,15 +258,20 @@ IEnumerator> IEnumerable>.
}
}
+ ///
void IDictionary.Add(TKey key, TValue value) => Add(value);
+ ///
void ICollection>.Add(KeyValuePair item) => Add(item.Value);
+ ///
bool ICollection>.Contains(KeyValuePair item) => ContainsKey(item.Key);
+ ///
void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) =>
throw new NotImplementedException();
+ ///
bool ICollection>.Remove(KeyValuePair item) => Remove(item.Key);
#endregion
diff --git a/src/Umbraco.Core/Collections/OrderedHashSet.cs b/src/Umbraco.Core/Collections/OrderedHashSet.cs
index d23c81a7b27d..71373d432314 100644
--- a/src/Umbraco.Core/Collections/OrderedHashSet.cs
+++ b/src/Umbraco.Core/Collections/OrderedHashSet.cs
@@ -13,8 +13,16 @@ public class OrderedHashSet : KeyedCollection
{
private readonly bool _keepOldest;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// When true , the oldest item is kept when a duplicate is added;
+ /// when false , the newest item replaces the oldest.
+ ///
public OrderedHashSet(bool keepOldest = true) => _keepOldest = keepOldest;
+ ///
protected override void InsertItem(int index, T item)
{
if (Dictionary == null)
@@ -42,5 +50,6 @@ protected override void InsertItem(int index, T item)
}
}
+ ///
protected override T GetKeyForItem(T item) => item;
}
diff --git a/src/Umbraco.Core/Collections/StackQueue.cs b/src/Umbraco.Core/Collections/StackQueue.cs
index 2324eec892ec..2d1982233b2e 100644
--- a/src/Umbraco.Core/Collections/StackQueue.cs
+++ b/src/Umbraco.Core/Collections/StackQueue.cs
@@ -8,14 +8,32 @@ public class StackQueue
{
private readonly LinkedList _linkedList = new();
+ ///
+ /// Gets the number of elements contained in the collection.
+ ///
public int Count => _linkedList.Count;
+ ///
+ /// Removes all elements from the collection.
+ ///
public void Clear() => _linkedList.Clear();
+ ///
+ /// Pushes an object onto the stack (adds to the front).
+ ///
+ /// The object to push onto the stack.
public void Push(T? obj) => _linkedList.AddFirst(obj);
+ ///
+ /// Adds an object to the queue (adds to the front).
+ ///
+ /// The object to add to the queue.
public void Enqueue(T? obj) => _linkedList.AddFirst(obj);
+ ///
+ /// Removes and returns the object at the top of the stack (from the front).
+ ///
+ /// The object removed from the top of the stack.
public T Pop()
{
var obj = default(T);
@@ -28,6 +46,10 @@ public T Pop()
return obj!;
}
+ ///
+ /// Removes and returns the object at the beginning of the queue (from the back).
+ ///
+ /// The object removed from the beginning of the queue.
public T Dequeue()
{
var obj = default(T);
@@ -40,7 +62,15 @@ public T Dequeue()
return obj!;
}
+ ///
+ /// Returns the object at the top of the stack without removing it.
+ ///
+ /// The object at the top of the stack, or the default value if the collection is empty.
public T? PeekStack() => _linkedList.First is not null ? _linkedList.First.Value : default;
+ ///
+ /// Returns the object at the beginning of the queue without removing it.
+ ///
+ /// The object at the beginning of the queue, or the default value if the collection is empty.
public T? PeekQueue() => _linkedList.Last is not null ? _linkedList.Last.Value : default;
}
diff --git a/src/Umbraco.Core/Collections/TopoGraph.cs b/src/Umbraco.Core/Collections/TopoGraph.cs
index fd2161c6d3a4..be68fff0a1c9 100644
--- a/src/Umbraco.Core/Collections/TopoGraph.cs
+++ b/src/Umbraco.Core/Collections/TopoGraph.cs
@@ -1,15 +1,45 @@
namespace Umbraco.Cms.Core.Collections;
+///
+/// Provides static methods and nested types for creating topologically sortable graph nodes.
+///
public class TopoGraph
{
+ ///
+ /// Error message used when a cyclic dependency is detected.
+ ///
internal const string CycleDependencyError = "Cyclic dependency.";
+
+ ///
+ /// Error message used when a required dependency is missing.
+ ///
internal const string MissingDependencyError = "Missing dependency.";
+ ///
+ /// Creates a new graph node with the specified key, item, and dependencies.
+ ///
+ /// The type of the key.
+ /// The type of the item.
+ /// The key that uniquely identifies the node.
+ /// The item stored in the node.
+ /// The keys of nodes that this node depends on.
+ /// A new instance.
public static Node CreateNode(TKey key, TItem item, IEnumerable dependencies) =>
new(key, item, dependencies);
+ ///
+ /// Represents a node in a topological graph with a key, item, and dependencies.
+ ///
+ /// The type of the key.
+ /// The type of the item.
public class Node
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The key that uniquely identifies the node.
+ /// The item stored in the node.
+ /// The keys of nodes that this node depends on.
public Node(TKey key, TItem item, IEnumerable dependencies)
{
Key = key;
@@ -17,10 +47,19 @@ public Node(TKey key, TItem item, IEnumerable dependencies)
Dependencies = dependencies;
}
+ ///
+ /// Gets the key that uniquely identifies this node.
+ ///
public TKey Key { get; }
+ ///
+ /// Gets the item stored in this node.
+ ///
public TItem Item { get; }
+ ///
+ /// Gets the keys of nodes that this node depends on.
+ ///
public IEnumerable Dependencies { get; }
}
}
@@ -92,9 +131,27 @@ public IEnumerable GetSortedItems(bool throwOnCycle = true, bool throwOnM
return sorted;
}
+ ///
+ /// Determines whether the specified item exists in the array within the given range.
+ ///
+ /// The array to search.
+ /// The item to locate.
+ /// The starting index of the search range.
+ /// The number of elements to search.
+ /// true if the item is found; otherwise, false .
private static bool Contains(TItem[] items, TItem item, int start, int count) =>
Array.IndexOf(items, item, start, count) >= 0;
+ ///
+ /// Recursively visits a node and its dependencies to perform topological sorting.
+ ///
+ /// The item to visit.
+ /// The set of already visited items.
+ /// The array to store sorted items.
+ /// The current index in the sorted array.
+ /// The increment direction (+1 for forward, -1 for reverse).
+ /// Whether to throw an exception on cyclic dependencies.
+ /// Whether to throw an exception on missing dependencies.
private void Visit(TItem item, ISet visited, TItem[] sorted, ref int index, int incr, bool throwOnCycle, bool throwOnMissing)
{
if (visited.Contains(item))
@@ -127,6 +184,12 @@ private void Visit(TItem item, ISet visited, TItem[] sorted, ref int inde
index += incr;
}
+ ///
+ /// Finds and returns the items corresponding to the specified dependency keys.
+ ///
+ /// The keys of the dependencies to find.
+ /// Whether to throw an exception if a dependency is not found.
+ /// An enumerable of items corresponding to the keys.
private IEnumerable FindDependencies(IEnumerable keys, bool throwOnMissing)
{
foreach (TKey key in keys)
diff --git a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
index 0a3baa1d3da8..b127b2f9a6b1 100644
--- a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
+++ b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
@@ -128,6 +128,13 @@ protected virtual IEnumerable CreateItems(IServiceProvider factory)
protected virtual TItem CreateItem(IServiceProvider factory, Type itemType)
=> (TItem)factory.GetRequiredService(itemType);
+ ///
+ /// Ensures that the specified type is valid for the collection.
+ ///
+ /// The type to validate.
+ /// The action being performed (used in error messages).
+ /// The validated type.
+ /// Thrown when the type does not inherit from or implement .
protected Type EnsureType(Type type, string action)
{
if (typeof(TItem).IsAssignableFrom(type) == false)
diff --git a/src/Umbraco.Core/Composing/ComponentCollection.cs b/src/Umbraco.Core/Composing/ComponentCollection.cs
index 3d1b2c5c2661..8b89af8d8402 100644
--- a/src/Umbraco.Core/Composing/ComponentCollection.cs
+++ b/src/Umbraco.Core/Composing/ComponentCollection.cs
@@ -14,6 +14,12 @@ public class ComponentCollection : BuilderCollectionBase
private readonly IProfilingLogger _profilingLogger;
private readonly ILogger _logger;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A factory function that provides the component items.
+ /// The profiling logger for timing component operations.
+ /// The logger for recording component lifecycle events.
public ComponentCollection(Func> items, IProfilingLogger profilingLogger, ILogger logger)
: base(items)
{
@@ -21,6 +27,12 @@ public ComponentCollection(Func> items, IProfilingL
_logger = logger;
}
+ ///
+ /// Initializes all components in the collection.
+ ///
+ /// If set to true indicates Umbraco is restarting.
+ /// The cancellation token. Cancellation indicates that the start process has been aborted.
+ /// A representing the asynchronous operation.
public async Task InitializeAsync(bool isRestarting, CancellationToken cancellationToken)
{
using (_profilingLogger.IsEnabled(Logging.LogLevel.Debug) is false
@@ -41,6 +53,12 @@ public async Task InitializeAsync(bool isRestarting, CancellationToken cancellat
}
}
+ ///
+ /// Terminates all components in the collection in reverse order.
+ ///
+ /// If set to true indicates Umbraco is restarting.
+ /// The cancellation token. Cancellation indicates that the shutdown process should no longer be graceful.
+ /// A representing the asynchronous operation.
public async Task TerminateAsync(bool isRestarting, CancellationToken cancellationToken)
{
using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug)
diff --git a/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs b/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs
index f4cdb802387e..847a5e7d30e6 100644
--- a/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs
+++ b/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs
@@ -10,8 +10,10 @@ public class ComponentCollectionBuilder : OrderedCollectionBuilderBase
protected override ComponentCollectionBuilder This => this;
+ ///
protected override IEnumerable CreateItems(IServiceProvider factory)
{
IProfilingLogger logger = factory.GetRequiredService();
@@ -24,6 +26,7 @@ protected override IEnumerable CreateItems(IServiceProvider fac
}
}
+ ///
protected override IAsyncComponent CreateItem(IServiceProvider factory, Type itemType)
{
IProfilingLogger logger = factory.GetRequiredService();
diff --git a/src/Umbraco.Core/Composing/ComposerGraph.cs b/src/Umbraco.Core/Composing/ComposerGraph.cs
index 0c376befd514..699d4ca466b8 100644
--- a/src/Umbraco.Core/Composing/ComposerGraph.cs
+++ b/src/Umbraco.Core/Composing/ComposerGraph.cs
@@ -62,6 +62,11 @@ public void Compose()
}
}
+ ///
+ /// Gets a formatted report of composers and their dependencies.
+ ///
+ /// A dictionary of types to their required dependencies.
+ /// A formatted string containing the composers report.
internal static string GetComposersReport(Dictionary?> requirements)
{
var text = new StringBuilder();
@@ -116,6 +121,10 @@ bool HasReq(IEnumerable types, Type type)
return text.ToString();
}
+ ///
+ /// Prepares and orders the composer types based on their dependencies.
+ ///
+ /// An ordered collection of composer types.
internal IEnumerable PrepareComposerTypes()
{
Dictionary?> requirements = GetRequirements();
@@ -134,6 +143,11 @@ internal IEnumerable PrepareComposerTypes()
return sortedComposerTypes;
}
+ ///
+ /// Gets the dependency requirements for all composer types.
+ ///
+ /// If set to true , throws an exception when required dependencies are missing.
+ /// A dictionary mapping each type to its required dependencies.
internal Dictionary?> GetRequirements(bool throwOnMissing = true)
{
// create a list, remove those that cannot be enabled due to runtime level
@@ -202,6 +216,11 @@ static void GatherInterfaces(Type type, Func getTy
return requirements;
}
+ ///
+ /// Sorts the composers based on their dependency requirements.
+ ///
+ /// A dictionary of types to their required dependencies.
+ /// A sorted collection of composer types.
internal IEnumerable SortComposers(Dictionary?> requirements)
{
// sort composers
@@ -415,10 +434,19 @@ private static IEnumerable InstantiateComposers(IEnumerable typ
}
}
+ ///
+ /// Stores enable/disable information for a composer type.
+ ///
private sealed class EnableInfo
{
+ ///
+ /// Gets or sets a value indicating whether the composer is enabled.
+ ///
public bool Enabled { get; set; }
+ ///
+ /// Gets or sets the weight of the enable/disable declaration.
+ ///
public int Weight { get; set; } = -1;
}
}
diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
index 0f1d0cc571b0..a3a29d27001a 100644
--- a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
+++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
@@ -19,6 +19,13 @@ public class DefaultUmbracoAssemblyProvider : IAssemblyProvider
private readonly ILoggerFactory _loggerFactory;
private List? _discovered;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The entry point assembly to scan from.
+ /// The logger factory for creating loggers.
+ /// Optional additional assembly names to include in scanning.
+ /// Thrown when is null.
public DefaultUmbracoAssemblyProvider(
Assembly? entryPointAssembly,
ILoggerFactory loggerFactory,
@@ -34,6 +41,8 @@ public DefaultUmbracoAssemblyProvider(
// that will still only resolve Assemblies that are already loaded but it would also make it possible to
// query dynamically generated assemblies once they are added. It would also provide the ability to probe
// assembly locations that are not in the same place as the entry point assemblies.
+
+ ///
public IEnumerable Assemblies
{
get
diff --git a/src/Umbraco.Core/Composing/DisableAttribute.cs b/src/Umbraco.Core/Composing/DisableAttribute.cs
index 09d638188da2..a81c803fb717 100644
--- a/src/Umbraco.Core/Composing/DisableAttribute.cs
+++ b/src/Umbraco.Core/Composing/DisableAttribute.cs
@@ -29,6 +29,11 @@ public DisableAttribute()
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The full type name of the composer to disable.
+ /// The assembly name containing the composer type.
public DisableAttribute(string fullTypeName, string assemblyName) =>
DisabledType = Assembly.Load(assemblyName)?.GetType(fullTypeName);
diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
index a1581ccfcb11..c7a76ab19199 100644
--- a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
+++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
@@ -38,6 +38,10 @@ public FindAssembliesWithReferencesTo(Assembly[] referenceAssemblies, string[] t
_logger = _loggerFactory.CreateLogger();
}
+ ///
+ /// Finds all assemblies that reference the target assemblies.
+ ///
+ /// A collection of assemblies that reference the target assemblies.
public IEnumerable Find()
{
var referenceItems = new List();
diff --git a/src/Umbraco.Core/Composing/HideFromTypeFinderAttribute.cs b/src/Umbraco.Core/Composing/HideFromTypeFinderAttribute.cs
index 4478deb5ac85..5744b1ca6e14 100644
--- a/src/Umbraco.Core/Composing/HideFromTypeFinderAttribute.cs
+++ b/src/Umbraco.Core/Composing/HideFromTypeFinderAttribute.cs
@@ -1,8 +1,11 @@
namespace Umbraco.Cms.Core.Composing;
///
-/// Notifies the TypeFinder that it should ignore the class marked with this attribute.
+/// Notifies the that it should ignore the class marked with this attribute.
///
+///
+/// Apply this attribute to classes that should not be discovered during type scanning operations.
+///
[AttributeUsage(AttributeTargets.Class)]
public sealed class HideFromTypeFinderAttribute : Attribute
{
diff --git a/src/Umbraco.Core/Composing/IAssemblyProvider.cs b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
index 4148c9ee4788..39629e82ce7e 100644
--- a/src/Umbraco.Core/Composing/IAssemblyProvider.cs
+++ b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
@@ -3,9 +3,12 @@
namespace Umbraco.Cms.Core.Composing;
///
-/// Provides a list of assemblies that can be scanned
+/// Provides a list of assemblies that can be scanned.
///
public interface IAssemblyProvider
{
+ ///
+ /// Gets the collection of assemblies available for type scanning.
+ ///
IEnumerable Assemblies { get; }
}
diff --git a/src/Umbraco.Core/Composing/IDiscoverable.cs b/src/Umbraco.Core/Composing/IDiscoverable.cs
index 848c70ddab7c..3e21738e4192 100644
--- a/src/Umbraco.Core/Composing/IDiscoverable.cs
+++ b/src/Umbraco.Core/Composing/IDiscoverable.cs
@@ -1,5 +1,13 @@
namespace Umbraco.Cms.Core.Composing;
+///
+/// Marker interface for types that should be discovered during type scanning.
+///
+///
+/// Types implementing this interface are cached during discovery operations,
+/// making subsequent lookups faster. Use this interface for plugin types that
+/// need to be discovered at runtime.
+///
public interface IDiscoverable
{
}
diff --git a/src/Umbraco.Core/Composing/IRuntimeHash.cs b/src/Umbraco.Core/Composing/IRuntimeHash.cs
index d641c9053803..dfff8d0c8a8d 100644
--- a/src/Umbraco.Core/Composing/IRuntimeHash.cs
+++ b/src/Umbraco.Core/Composing/IRuntimeHash.cs
@@ -1,13 +1,17 @@
namespace Umbraco.Cms.Core.Composing;
///
-/// Used to create a hash value of the current runtime
+/// Used to create a hash value of the current runtime.
///
///
-/// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
-/// part of the application has changed. This is used to detect if we need to re-type scan.
+/// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
+/// part of the application has changed. This is used to detect if we need to re-type scan.
///
public interface IRuntimeHash
{
+ ///
+ /// Gets the hash value representing the current runtime state.
+ ///
+ /// A string hash value that changes when the runtime changes.
string GetHashValue();
}
diff --git a/src/Umbraco.Core/Composing/ITypeFinder.cs b/src/Umbraco.Core/Composing/ITypeFinder.cs
index 4bebfae33467..221fc934b80a 100644
--- a/src/Umbraco.Core/Composing/ITypeFinder.cs
+++ b/src/Umbraco.Core/Composing/ITypeFinder.cs
@@ -10,9 +10,14 @@ public interface ITypeFinder
///
/// Return a list of found local Assemblies that Umbraco should scan for type finding
///
- ///
+ /// The assemblies to scan.
IEnumerable AssembliesToScan { get; }
+ ///
+ /// Gets a type by its full name.
+ ///
+ /// The full name of the type to find.
+ /// The type if found; otherwise, null .
Type? GetTypeByName(string name);
///
diff --git a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs
index 49ada40dfa42..adf05517c27b 100644
--- a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs
+++ b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs
@@ -17,6 +17,9 @@ public abstract class
private readonly List _excluded = new();
private readonly List>> _producers = new();
+ ///
+ /// Gets the current builder instance.
+ ///
protected abstract TBuilder This { get; }
///
@@ -122,6 +125,7 @@ public TBuilder Exclude(Type type)
return This;
}
+ ///
protected override IEnumerable GetRegisteringTypes(IEnumerable types) =>
types
.Union(_producers.SelectMany(x => x()))
diff --git a/src/Umbraco.Core/Composing/LazyReadOnlyCollection.cs b/src/Umbraco.Core/Composing/LazyReadOnlyCollection.cs
index eb6f2ed055af..08bf6f18d4c8 100644
--- a/src/Umbraco.Core/Composing/LazyReadOnlyCollection.cs
+++ b/src/Umbraco.Core/Composing/LazyReadOnlyCollection.cs
@@ -2,18 +2,34 @@
namespace Umbraco.Cms.Core.Composing;
+///
+/// Represents a lazily-initialized read-only collection.
+///
+/// The type of elements in the collection.
public sealed class LazyReadOnlyCollection : IReadOnlyCollection
{
private readonly Lazy> _lazyCollection;
private int? _count;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A lazy wrapper containing the collection factory.
public LazyReadOnlyCollection(Lazy> lazyCollection) => _lazyCollection = lazyCollection;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A factory function that creates the collection when first accessed.
public LazyReadOnlyCollection(Func> lazyCollection) =>
_lazyCollection = new Lazy>(lazyCollection);
+ ///
+ /// Gets the underlying collection value.
+ ///
public IEnumerable Value => EnsureCollection();
+ ///
public int Count
{
get
@@ -23,8 +39,10 @@ public int Count
}
}
+ ///
public IEnumerator GetEnumerator() => Value.GetEnumerator();
+ ///
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
private IEnumerable EnsureCollection()
diff --git a/src/Umbraco.Core/Composing/LazyResolve.cs b/src/Umbraco.Core/Composing/LazyResolve.cs
index 723d9afe2e35..96b2d278baab 100644
--- a/src/Umbraco.Core/Composing/LazyResolve.cs
+++ b/src/Umbraco.Core/Composing/LazyResolve.cs
@@ -2,9 +2,21 @@
namespace Umbraco.Cms.Core.Composing;
+///
+/// Provides lazy resolution of a service from the dependency injection container.
+///
+/// The type of service to resolve.
+///
+/// This class defers service resolution until the property is accessed,
+/// which can help avoid circular dependency issues during application startup.
+///
public class LazyResolve : Lazy
where T : class
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The service provider used to resolve the service.
public LazyResolve(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService)
{
diff --git a/src/Umbraco.Core/Composing/OrderedCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/OrderedCollectionBuilderBase.cs
index d9c733da7d18..394658808009 100644
--- a/src/Umbraco.Core/Composing/OrderedCollectionBuilderBase.cs
+++ b/src/Umbraco.Core/Composing/OrderedCollectionBuilderBase.cs
@@ -10,6 +10,9 @@ public abstract class OrderedCollectionBuilderBase
where TBuilder : OrderedCollectionBuilderBase
where TCollection : class, IBuilderCollection