From aa9569c20388e2219a7acd90d172113b35072b00 Mon Sep 17 00:00:00 2001 From: Brandon Henricks Date: Wed, 8 Jan 2025 16:11:24 -0500 Subject: [PATCH 1/2] Add IMediaFileRepository and implement caching logic Introduced IMediaFileRepository interface with async methods for retrieving media files. Added MediaFileRepository class implementing the interface, utilizing IProgressiveCache and ObjectQuery for caching and querying. Updated DependencyInjection to register the new service with TryAddScoped. --- .../DependencyInjection.cs | 2 + .../Interfaces/IMediaFileRepository.cs | 29 +++++ .../MediaFileRepository.cs | 100 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 src/XperienceCommunity.DataRepository/Interfaces/IMediaFileRepository.cs create mode 100644 src/XperienceCommunity.DataRepository/MediaFileRepository.cs diff --git a/src/XperienceCommunity.DataRepository/DependencyInjection.cs b/src/XperienceCommunity.DataRepository/DependencyInjection.cs index ceeedf4..d255e5f 100644 --- a/src/XperienceCommunity.DataRepository/DependencyInjection.cs +++ b/src/XperienceCommunity.DataRepository/DependencyInjection.cs @@ -33,6 +33,8 @@ public static IServiceCollection AddXperienceDataRepositories(this IServiceColle services.TryAddScoped(typeof(IPageRepository<>), typeof(PageTypeRepository<>)); + services.TryAddScoped(); + return services; } } diff --git a/src/XperienceCommunity.DataRepository/Interfaces/IMediaFileRepository.cs b/src/XperienceCommunity.DataRepository/Interfaces/IMediaFileRepository.cs new file mode 100644 index 0000000..fb2533f --- /dev/null +++ b/src/XperienceCommunity.DataRepository/Interfaces/IMediaFileRepository.cs @@ -0,0 +1,29 @@ +using System.Collections.Immutable; + +using CMS.MediaLibrary; + +namespace XperienceCommunity.DataRepository.Interfaces; + +/// +/// Interface for media file repository to handle media file operations. +/// +public interface IMediaFileRepository +{ + /// + /// Retrieves a list of media files based on the provided GUIDs. + /// + /// The GUIDs of the media files to retrieve. + /// A token to monitor for cancellation requests. + /// A task that represents the asynchronous operation. The task result contains an immutable list of . + Task> GetMediaFilesAsync(IEnumerable mediaFileGuids, + CancellationToken cancellationToken = default); + + /// + /// Retrieves a list of media files based on the provided related items. + /// + /// The related items to retrieve media files from. + /// A token to monitor for cancellation requests. + /// A task that represents the asynchronous operation. The task result contains an immutable list of . + Task> GetAssetsFromRelatedItemsAsync(IEnumerable items, + CancellationToken cancellationToken = default); +} diff --git a/src/XperienceCommunity.DataRepository/MediaFileRepository.cs b/src/XperienceCommunity.DataRepository/MediaFileRepository.cs new file mode 100644 index 0000000..6703da9 --- /dev/null +++ b/src/XperienceCommunity.DataRepository/MediaFileRepository.cs @@ -0,0 +1,100 @@ +using System.Collections.Immutable; + +using CMS.DataEngine; +using CMS.Helpers; +using CMS.MediaLibrary; + +using XperienceCommunity.DataRepository.Interfaces; +using XperienceCommunity.DataRepository.Models; + +namespace XperienceCommunity.DataRepository; + +public sealed class MediaFileRepository : IMediaFileRepository +{ + private readonly IProgressiveCache _cache; + private readonly int _cacheMinutes; + + public MediaFileRepository(IProgressiveCache cache, RepositoryOptions options) + { + _cache = cache; + _cacheMinutes = options?.CacheMinutes ?? 10; + } + + public async Task> GetAssetsFromRelatedItemsAsync(IEnumerable items, + CancellationToken cancellationToken = default) + { + var assetItems = items?.ToList() ?? []; + + if (assetItems.Count == 0) + { + return []; + } + + return await _cache.LoadAsync( + async (cacheSettings, ct) => + { + var results = (await new ObjectQuery() + .ForAssets(assetItems) + .GetEnumerableTypedResultAsync(cancellationToken: ct)) + .ToList() ?? []; + + string[] dependencyKeys = results + .Select(result => $"mediafile|{result.FileGUID}") + .ToArray(); + + cacheSettings.CacheDependency = CacheHelper.GetCacheDependency(dependencyKeys); + + return results.ToImmutableList(); + }, + new CacheSettings( + cacheMinutes: _cacheMinutes, + useSlidingExpiration: true, + cacheItemNameParts: + [ + nameof(MediaFileRepository), + nameof(GetAssetsFromRelatedItemsAsync), + .. assetItems.OrderBy(item => item.Name).Select(item => item.Name) ?? [], + ] + ), cancellationToken + ); + } + + public async Task> GetMediaFilesAsync(IEnumerable mediaFileGuids, + CancellationToken cancellationToken = default) + { + var guidList = mediaFileGuids?.ToList() ?? []; + + if (guidList.Count == 0) + { + return []; + } + + return await _cache.LoadAsync( + async (cacheSettings, ct) => + { + var results = (await new ObjectQuery() + .WhereIn(nameof(MediaFileInfo.FileGUID), guidList) + .GetEnumerableTypedResultAsync(cancellationToken: ct)) + ?.ToList() ?? []; + + string[] dependencyKeys = guidList + .Select(x => $"mediafile|{x}") + .ToArray(); + + cacheSettings.CacheDependency = CacheHelper.GetCacheDependency(dependencyKeys); + + return results.ToImmutableList(); + }, + new CacheSettings( + cacheMinutes: _cacheMinutes, + useSlidingExpiration: true, + cacheItemNameParts: + [ + nameof(MediaFileRepository), + nameof(GetMediaFilesAsync), + guidList.GetHashCode(), + ] + ), cancellationToken + ); + } +} From 67ae0bfad1aa2a89e520f247fca08a53eb206036 Mon Sep 17 00:00:00 2001 From: Brandon Henricks Date: Wed, 8 Jan 2025 16:17:15 -0500 Subject: [PATCH 2/2] Refactor: Rename private fields in MediaFileRepository Renamed private fields `_cache` to `cache` and `_cacheMinutes` to `cacheMinutes` in `MediaFileRepository.cs` to follow a consistent naming convention. Updated constructor and method calls to reflect these changes. --- .../MediaFileRepository.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/XperienceCommunity.DataRepository/MediaFileRepository.cs b/src/XperienceCommunity.DataRepository/MediaFileRepository.cs index 6703da9..aeaac5b 100644 --- a/src/XperienceCommunity.DataRepository/MediaFileRepository.cs +++ b/src/XperienceCommunity.DataRepository/MediaFileRepository.cs @@ -11,13 +11,13 @@ namespace XperienceCommunity.DataRepository; public sealed class MediaFileRepository : IMediaFileRepository { - private readonly IProgressiveCache _cache; - private readonly int _cacheMinutes; + private readonly IProgressiveCache cache; + private readonly int cacheMinutes; public MediaFileRepository(IProgressiveCache cache, RepositoryOptions options) { - _cache = cache; - _cacheMinutes = options?.CacheMinutes ?? 10; + this.cache = cache; + cacheMinutes = options?.CacheMinutes ?? 10; } public async Task> GetAssetsFromRelatedItemsAsync(IEnumerable items, @@ -30,7 +30,7 @@ public async Task> GetAssetsFromRelatedItemsAsync(I return []; } - return await _cache.LoadAsync( + return await cache.LoadAsync( async (cacheSettings, ct) => { var results = (await new ObjectQuery() @@ -47,7 +47,7 @@ public async Task> GetAssetsFromRelatedItemsAsync(I return results.ToImmutableList(); }, new CacheSettings( - cacheMinutes: _cacheMinutes, + cacheMinutes: cacheMinutes, useSlidingExpiration: true, cacheItemNameParts: [ @@ -69,7 +69,7 @@ public async Task> GetMediaFilesAsync(IEnumerable { var results = (await new ObjectQuery() @@ -86,7 +86,7 @@ public async Task> GetMediaFilesAsync(IEnumerable