Files
Umbraco-CMS/src/Umbraco.Core/Cache/DeepCloneAppCache.cs

179 lines
5.8 KiB
C#
Raw Normal View History

2019-01-17 11:01:23 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
Merge remote-tracking branch 'origin/v8/8.16' into v9/feature/merge_v8_11082021 # Conflicts: # .github/CONTRIBUTING.md # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.Web.nuspec # build/NuSpecs/UmbracoCms.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/AppCaches.cs # src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs # src/Umbraco.Core/Cache/DeepCloneAppCache.cs # src/Umbraco.Core/Cache/WebCachingAppCache.cs # src/Umbraco.Core/CompositionExtensions.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Models/PropertyGroupCollection.cs # src/Umbraco.Core/Models/PropertyTypeCollection.cs # src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs # src/Umbraco.Core/ReadLock.cs # src/Umbraco.Core/Routing/SiteDomainMapper.cs # src/Umbraco.Core/UpgradeableReadLock.cs # src/Umbraco.Core/WriteLock.cs # src/Umbraco.Examine/ExamineExtensions.cs # src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs # src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeDto.cs # src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs # src/Umbraco.Infrastructure/Services/IdKeyMap.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs # src/Umbraco.Tests/App.config # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.UI.Client/package.json # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco.Web.UI.csproj # src/Umbraco.Web.UI/Umbraco/config/lang/cy.xml # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/CacheHelperExtensions.cs # src/Umbraco.Web/Editors/RelationTypeController.cs # src/Umbraco.Web/Logging/WebProfilerProvider.cs # src/Umbraco.Web/Models/Mapping/MemberMapDefinition.cs # src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs # src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Security/BackOfficeUserManager.cs # src/Umbraco.Web/Umbraco.Web.csproj
2021-08-11 19:11:35 +02:00
using Umbraco.Extensions;
2019-01-17 11:01:23 +01:00
namespace Umbraco.Cms.Core.Cache
2019-01-17 11:01:23 +01:00
{
/// <summary>
2019-01-18 07:56:38 +01:00
/// Implements <see cref="IAppPolicyCache"/> by wrapping an inner other <see cref="IAppPolicyCache"/>
2019-01-17 11:01:23 +01:00
/// instance, and ensuring that all inserts and returns are deep cloned copies of the cache item,
/// when the item is deep-cloneable.
/// </summary>
Merge remote-tracking branch 'origin/v8/8.16' into v9/feature/merge_v8_11082021 # Conflicts: # .github/CONTRIBUTING.md # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.Web.nuspec # build/NuSpecs/UmbracoCms.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/AppCaches.cs # src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs # src/Umbraco.Core/Cache/DeepCloneAppCache.cs # src/Umbraco.Core/Cache/WebCachingAppCache.cs # src/Umbraco.Core/CompositionExtensions.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Models/PropertyGroupCollection.cs # src/Umbraco.Core/Models/PropertyTypeCollection.cs # src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs # src/Umbraco.Core/ReadLock.cs # src/Umbraco.Core/Routing/SiteDomainMapper.cs # src/Umbraco.Core/UpgradeableReadLock.cs # src/Umbraco.Core/WriteLock.cs # src/Umbraco.Examine/ExamineExtensions.cs # src/Umbraco.Infrastructure/Examine/UmbracoFieldDefinitionCollection.cs # src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeDto.cs # src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs # src/Umbraco.Infrastructure/Services/IdKeyMap.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs # src/Umbraco.Tests/App.config # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.UI.Client/package.json # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco.Web.UI.csproj # src/Umbraco.Web.UI/Umbraco/config/lang/cy.xml # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/CacheHelperExtensions.cs # src/Umbraco.Web/Editors/RelationTypeController.cs # src/Umbraco.Web/Logging/WebProfilerProvider.cs # src/Umbraco.Web/Models/Mapping/MemberMapDefinition.cs # src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs # src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Security/BackOfficeUserManager.cs # src/Umbraco.Web/Umbraco.Web.csproj
2021-08-11 19:11:35 +02:00
public class DeepCloneAppCache : IAppPolicyCache, IDisposable
2019-01-17 11:01:23 +01:00
{
private bool _disposedValue;
2019-01-17 11:01:23 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="DeepCloneAppCache"/> class.
/// </summary>
2019-01-18 07:56:38 +01:00
public DeepCloneAppCache(IAppPolicyCache innerCache)
2019-01-17 11:01:23 +01:00
{
var type = typeof (DeepCloneAppCache);
if (innerCache.GetType() == type)
throw new InvalidOperationException($"A {type} cannot wrap another instance of itself.");
InnerCache = innerCache;
}
/// <summary>
/// Gets the inner cache.
/// </summary>
private IAppPolicyCache InnerCache { get; }
2019-01-17 11:01:23 +01:00
/// <inheritdoc />
public object? Get(string key)
2019-01-17 11:01:23 +01:00
{
var item = InnerCache.Get(key);
return CheckCloneableAndTracksChanges(item);
}
/// <inheritdoc />
public object? Get(string key, Func<object?> factory)
2019-01-17 11:01:23 +01:00
{
var cached = InnerCache.Get(key, () =>
{
var result = SafeLazy.GetSafeLazy(factory);
2019-01-17 11:01:23 +01:00
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
// do not store null values (backward compat), clone / reset to go into the cache
return value == null ? null : CheckCloneableAndTracksChanges(value);
});
return CheckCloneableAndTracksChanges(cached);
}
/// <inheritdoc />
public IEnumerable<object?> SearchByKey(string keyStartsWith)
2019-01-17 11:01:23 +01:00
{
return InnerCache.SearchByKey(keyStartsWith)
.Select(CheckCloneableAndTracksChanges);
}
/// <inheritdoc />
public IEnumerable<object?> SearchByRegex(string regex)
2019-01-17 11:01:23 +01:00
{
return InnerCache.SearchByRegex(regex)
.Select(CheckCloneableAndTracksChanges);
}
/// <inheritdoc />
public object? Get(string key, Func<object?> factory, TimeSpan? timeout, bool isSliding = false, string[]? dependentFiles = null)
2019-01-17 11:01:23 +01:00
{
var cached = InnerCache.Get(key, () =>
{
var result = SafeLazy.GetSafeLazy(factory);
2019-01-17 11:01:23 +01:00
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
// do not store null values (backward compat), clone / reset to go into the cache
return value == null ? null : CheckCloneableAndTracksChanges(value);
2019-01-17 11:01:23 +01:00
// clone / reset to go into the cache
}, timeout, isSliding, dependentFiles);
2019-01-17 11:01:23 +01:00
// clone / reset to go into the cache
return CheckCloneableAndTracksChanges(cached);
}
/// <inheritdoc />
public void Insert(string key, Func<object?> factory, TimeSpan? timeout = null, bool isSliding = false, string[]? dependentFiles = null)
2019-01-17 11:01:23 +01:00
{
InnerCache.Insert(key, () =>
{
var result = SafeLazy.GetSafeLazy(factory);
2019-01-17 11:01:23 +01:00
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
// do not store null values (backward compat), clone / reset to go into the cache
return value == null ? null : CheckCloneableAndTracksChanges(value);
}, timeout, isSliding, dependentFiles);
2019-01-17 11:01:23 +01:00
}
/// <inheritdoc />
public void Clear()
{
InnerCache.Clear();
}
/// <inheritdoc />
public void Clear(string key)
{
InnerCache.Clear(key);
}
/// <inheritdoc />
public void ClearOfType(Type type)
2019-01-17 11:01:23 +01:00
{
InnerCache.ClearOfType(type);
2019-01-17 11:01:23 +01:00
}
/// <inheritdoc />
public void ClearOfType<T>()
{
InnerCache.ClearOfType<T>();
}
/// <inheritdoc />
public void ClearOfType<T>(Func<string, T, bool> predicate)
{
InnerCache.ClearOfType<T>(predicate);
}
/// <inheritdoc />
public void ClearByKey(string keyStartsWith)
{
InnerCache.ClearByKey(keyStartsWith);
}
/// <inheritdoc />
public void ClearByRegex(string regex)
{
InnerCache.ClearByRegex(regex);
}
private static object? CheckCloneableAndTracksChanges(object? input)
2019-01-17 11:01:23 +01:00
{
if (input is IDeepCloneable cloneable)
{
input = cloneable.DeepClone();
}
// reset dirty initial properties
if (input is IRememberBeingDirty tracksChanges)
{
tracksChanges.ResetDirtyProperties(false);
input = tracksChanges;
}
return input;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
InnerCache.DisposeIfDisposable();
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
}
2019-01-17 11:01:23 +01:00
}
}