Updates the caching layer to handle GUID keys for content types while preserving backwards compat, fixes unit tests, removes the strongly typed lists for the block editor value since it's unecessary
This commit is contained in:
@@ -7,6 +7,16 @@ using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
public interface IPublishedCache2 : IPublishedCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a content type identified by its alias.
|
||||
/// </summary>
|
||||
/// <param name="key">The content type key.</param>
|
||||
/// <returns>The content type, or null.</returns>
|
||||
IPublishedContentType GetContentType(Guid key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to cached contents.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,11 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
public interface IPublishedContentCache2 : IPublishedContentCache, IPublishedCache2
|
||||
{
|
||||
// NOTE: this is here purely to avoid API breaking changes
|
||||
}
|
||||
|
||||
public interface IPublishedContentCache : IPublishedCache
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
public interface IPublishedMediaCache2 : IPublishedMediaCache, IPublishedCache2
|
||||
{
|
||||
// NOTE: this is here purely to avoid API breaking changes
|
||||
}
|
||||
|
||||
public interface IPublishedMediaCache : IPublishedCache
|
||||
{ }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using Umbraco.Web.PublishedCache.NuCache.Navigable;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache
|
||||
{
|
||||
internal class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable
|
||||
internal class ContentCache : PublishedCacheBase, IPublishedContentCache2, INavigableData, IDisposable
|
||||
{
|
||||
private readonly ContentStore.Snapshot _snapshot;
|
||||
private readonly IAppCache _snapshotCache;
|
||||
@@ -384,15 +384,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
#region Content types
|
||||
|
||||
public override IPublishedContentType GetContentType(int id)
|
||||
{
|
||||
return _snapshot.GetContentType(id);
|
||||
}
|
||||
public override IPublishedContentType GetContentType(int id) => _snapshot.GetContentType(id);
|
||||
|
||||
public override IPublishedContentType GetContentType(string alias)
|
||||
{
|
||||
return _snapshot.GetContentType(alias);
|
||||
}
|
||||
public override IPublishedContentType GetContentType(string alias) => _snapshot.GetContentType(alias);
|
||||
|
||||
public override IPublishedContentType GetContentType(Guid key) => _snapshot.GetContentType(key);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -37,9 +37,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
private readonly IVariationContextAccessor _variationContextAccessor;
|
||||
private readonly ConcurrentDictionary<int, LinkedNode<ContentNode>> _contentNodes;
|
||||
private LinkedNode<ContentNode> _root;
|
||||
private readonly ConcurrentDictionary<int, LinkedNode<IPublishedContentType>> _contentTypesById;
|
||||
|
||||
// We must keep separate dictionaries for by id and by alias because we track these in snapshot/layers
|
||||
// and it is possible that the alias of a content type can be different for the same id in another layer
|
||||
// whereas the GUID -> INT cross reference can never be different
|
||||
private readonly ConcurrentDictionary<int, LinkedNode<IPublishedContentType>> _contentTypesById;
|
||||
private readonly ConcurrentDictionary<string, LinkedNode<IPublishedContentType>> _contentTypesByAlias;
|
||||
private readonly ConcurrentDictionary<Guid, int> _xmap;
|
||||
private readonly ConcurrentDictionary<Guid, int> _contentTypeKeyToIdMap;
|
||||
private readonly ConcurrentDictionary<Guid, int> _contentKeyToIdMap;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private BPlusTree<int, ContentNodeKit> _localDb;
|
||||
@@ -73,7 +78,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
_root = new LinkedNode<ContentNode>(new ContentNode(), 0);
|
||||
_contentTypesById = new ConcurrentDictionary<int, LinkedNode<IPublishedContentType>>();
|
||||
_contentTypesByAlias = new ConcurrentDictionary<string, LinkedNode<IPublishedContentType>>(StringComparer.InvariantCultureIgnoreCase);
|
||||
_xmap = new ConcurrentDictionary<Guid, int>();
|
||||
_contentTypeKeyToIdMap = new ConcurrentDictionary<Guid, int>();
|
||||
_contentKeyToIdMap = new ConcurrentDictionary<Guid, int>();
|
||||
|
||||
_genObjs = new ConcurrentQueue<GenObj>();
|
||||
_genObj = null; // no initial gen exists
|
||||
@@ -136,7 +142,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
Monitor.Enter(_wlocko, ref lockInfo.Taken);
|
||||
|
||||
lock(_rlocko)
|
||||
lock (_rlocko)
|
||||
{
|
||||
// see SnapDictionary
|
||||
try { }
|
||||
@@ -152,7 +158,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
_nextGen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Release(WriteLockInfo lockInfo, bool commit = true)
|
||||
@@ -291,8 +297,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
SetValueLocked(_contentTypesById, type.Id, type);
|
||||
SetValueLocked(_contentTypesByAlias, type.Alias, type);
|
||||
SetContentTypeLocked(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,8 +323,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
foreach (var type in index.Values)
|
||||
{
|
||||
SetValueLocked(_contentTypesById, type.Id, type);
|
||||
SetValueLocked(_contentTypesByAlias, type.Alias, type);
|
||||
SetContentTypeLocked(type);
|
||||
}
|
||||
|
||||
foreach (var link in _contentNodes.Values)
|
||||
@@ -354,8 +358,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
// set all new content types
|
||||
foreach (var type in types)
|
||||
{
|
||||
SetValueLocked(_contentTypesById, type.Id, type);
|
||||
SetValueLocked(_contentTypesByAlias, type.Alias, type);
|
||||
SetContentTypeLocked(type);
|
||||
}
|
||||
|
||||
// beware! at that point the cache is inconsistent,
|
||||
@@ -419,8 +422,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
// perform update of refreshed content types
|
||||
foreach (var type in refreshedTypesA)
|
||||
{
|
||||
SetValueLocked(_contentTypesById, type.Id, type);
|
||||
SetValueLocked(_contentTypesByAlias, type.Alias, type);
|
||||
SetContentTypeLocked(type);
|
||||
}
|
||||
|
||||
// perform update of content with refreshed content type - from the kits
|
||||
@@ -638,7 +640,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
kit.Node.PreviousSiblingContentId = existing.PreviousSiblingContentId;
|
||||
}
|
||||
|
||||
_xmap[kit.Node.Uid] = kit.Node.Id;
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -734,7 +736,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
// this node becomes the previous node
|
||||
previousNode = thisNode;
|
||||
|
||||
_xmap[kit.Node.Uid] = kit.Node.Id;
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
}
|
||||
|
||||
return ok;
|
||||
@@ -757,7 +759,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
EnsureLocked();
|
||||
|
||||
var ok = true;
|
||||
|
||||
|
||||
ClearLocked(_contentNodes);
|
||||
ClearRootLocked();
|
||||
|
||||
@@ -778,7 +780,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
if (_localDb != null) RegisterChange(kit.Node.Id, kit);
|
||||
AddTreeNodeLocked(kit.Node, parent);
|
||||
|
||||
_xmap[kit.Node.Uid] = kit.Node.Id;
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
}
|
||||
|
||||
return ok;
|
||||
@@ -807,7 +809,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
EnsureLocked();
|
||||
|
||||
var ok = true;
|
||||
|
||||
|
||||
// get existing
|
||||
_contentNodes.TryGetValue(rootContentId, out var link);
|
||||
var existing = link?.Value;
|
||||
@@ -833,7 +835,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
if (_localDb != null) RegisterChange(kit.Node.Id, kit);
|
||||
AddTreeNodeLocked(kit.Node, parent);
|
||||
|
||||
_xmap[kit.Node.Uid] = kit.Node.Id;
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
}
|
||||
|
||||
return ok;
|
||||
@@ -885,11 +887,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
// This should never be null, all code that calls this method is null checking but we've seen
|
||||
// issues of null ref exceptions in issue reports so we'll double check here
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
|
||||
|
||||
SetValueLocked(_contentNodes, content.Id, null);
|
||||
if (_localDb != null) RegisterChange(content.Id, ContentNodeKit.Null);
|
||||
|
||||
_xmap.TryRemove(content.Uid, out _);
|
||||
_contentKeyToIdMap.TryRemove(content.Uid, out _);
|
||||
|
||||
var id = content.FirstChildContentId;
|
||||
while (id > 0)
|
||||
@@ -913,10 +915,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
{
|
||||
if (_contentNodes.TryGetValue(id, out var link))
|
||||
{
|
||||
link = GetLinkedNodeGen(link, gen);
|
||||
link = GetLinkedNodeGen(link, gen);
|
||||
if (link != null && link.Value != null)
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
throw new PanicException($"failed to get {description} with id={id}");
|
||||
}
|
||||
@@ -929,13 +931,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
{
|
||||
if (content.ParentContentId < 0)
|
||||
{
|
||||
var root = GetLinkedNodeGen(_root, gen);
|
||||
var root = GetLinkedNodeGen(_root, gen);
|
||||
return root;
|
||||
}
|
||||
|
||||
if (_contentNodes.TryGetValue(content.ParentContentId, out var link))
|
||||
link = GetLinkedNodeGen(link, gen);
|
||||
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
@@ -1154,6 +1156,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
}
|
||||
}
|
||||
|
||||
private void SetContentTypeLocked(IPublishedContentType type)
|
||||
{
|
||||
SetValueLocked(_contentTypesById, type.Id, type);
|
||||
SetValueLocked(_contentTypesByAlias, type.Alias, type);
|
||||
// ensure the key/id map is accurate
|
||||
if (type.TryGetKey(out var key))
|
||||
_contentTypeKeyToIdMap[key] = type.Id;
|
||||
}
|
||||
|
||||
// set a node (just the node, not the tree)
|
||||
private void SetValueLocked<TKey, TValue>(ConcurrentDictionary<TKey, LinkedNode<TValue>> dict, TKey key, TValue value)
|
||||
where TValue : class
|
||||
@@ -1211,14 +1222,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
public ContentNode Get(Guid uid, long gen)
|
||||
{
|
||||
return _xmap.TryGetValue(uid, out var id)
|
||||
return _contentKeyToIdMap.TryGetValue(uid, out var id)
|
||||
? GetValue(_contentNodes, id, gen)
|
||||
: null;
|
||||
}
|
||||
|
||||
public IEnumerable<ContentNode> GetAtRoot(long gen)
|
||||
{
|
||||
var root = GetLinkedNodeGen(_root, gen);
|
||||
var root = GetLinkedNodeGen(_root, gen);
|
||||
if (root == null)
|
||||
yield break;
|
||||
|
||||
@@ -1274,13 +1285,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
return GetValue(_contentTypesByAlias, alias, gen);
|
||||
}
|
||||
|
||||
public IPublishedContentType GetContentType(Guid key, long gen)
|
||||
{
|
||||
if (!_contentTypeKeyToIdMap.TryGetValue(key, out var id))
|
||||
return null;
|
||||
return GetContentType(id, gen);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Snapshots
|
||||
|
||||
public Snapshot CreateSnapshot()
|
||||
{
|
||||
lock(_rlocko)
|
||||
lock (_rlocko)
|
||||
{
|
||||
// if no next generation is required, and we already have one,
|
||||
// use it and create a new snapshot
|
||||
@@ -1606,6 +1624,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
return _store.GetContentType(alias, _gen);
|
||||
}
|
||||
|
||||
public IPublishedContentType GetContentType(Guid key)
|
||||
{
|
||||
if (_gen < 0)
|
||||
throw new ObjectDisposedException("snapshot" /*+ " (" + _thisCount + ")"*/);
|
||||
return _store.GetContentType(key, _gen);
|
||||
}
|
||||
|
||||
// this code is here just so you don't try to implement it
|
||||
// the only way we can iterate over "all" without locking the entire cache forever
|
||||
// is by shallow cloning the cache, which is quite expensive, so we should probably not do it,
|
||||
|
||||
@@ -11,7 +11,7 @@ using Umbraco.Web.PublishedCache.NuCache.Navigable;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache
|
||||
{
|
||||
internal class MediaCache : PublishedCacheBase, IPublishedMediaCache, INavigableData, IDisposable
|
||||
internal class MediaCache : PublishedCacheBase, IPublishedMediaCache2, INavigableData, IDisposable
|
||||
{
|
||||
private readonly ContentStore.Snapshot _snapshot;
|
||||
private readonly IVariationContextAccessor _variationContextAccessor;
|
||||
@@ -155,15 +155,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
#region Content types
|
||||
|
||||
public override IPublishedContentType GetContentType(int id)
|
||||
{
|
||||
return _snapshot.GetContentType(id);
|
||||
}
|
||||
public override IPublishedContentType GetContentType(int id) => _snapshot.GetContentType(id);
|
||||
|
||||
public override IPublishedContentType GetContentType(string alias)
|
||||
{
|
||||
return _snapshot.GetContentType(alias);
|
||||
}
|
||||
public override IPublishedContentType GetContentType(string alias) => _snapshot.GetContentType(alias);
|
||||
|
||||
public override IPublishedContentType GetContentType(Guid key) => _snapshot.GetContentType(key);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
abstract class PublishedCacheBase : IPublishedCache
|
||||
internal abstract class PublishedCacheBase : IPublishedCache2
|
||||
{
|
||||
public bool PreviewDefault { get; }
|
||||
|
||||
@@ -89,8 +89,8 @@ namespace Umbraco.Web.PublishedCache
|
||||
}
|
||||
|
||||
public abstract IPublishedContentType GetContentType(int id);
|
||||
|
||||
public abstract IPublishedContentType GetContentType(string alias);
|
||||
public abstract IPublishedContentType GetContentType(Guid key);
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)
|
||||
{
|
||||
|
||||
@@ -15,8 +15,10 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <remarks>This cache is not snapshotted, so it refreshes any time things change.</remarks>
|
||||
public class PublishedContentTypeCache
|
||||
{
|
||||
// NOTE: These are not concurrent dictionaries because all access is done within a lock
|
||||
private readonly Dictionary<string, IPublishedContentType> _typesByAlias = new Dictionary<string, IPublishedContentType>();
|
||||
private readonly Dictionary<int, IPublishedContentType> _typesById = new Dictionary<int, IPublishedContentType>();
|
||||
private readonly Dictionary<Guid, int> _keyToIdMap = new Dictionary<Guid, int>();
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly IMediaTypeService _mediaTypeService;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
@@ -130,6 +132,42 @@ namespace Umbraco.Web.PublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a published content type.
|
||||
/// </summary>
|
||||
/// <param name="itemType">An item type.</param>
|
||||
/// <param name="key">An key.</param>
|
||||
/// <returns>The published content type corresponding to the item key.</returns>
|
||||
public IPublishedContentType Get(PublishedItemType itemType, Guid key)
|
||||
{
|
||||
try
|
||||
{
|
||||
_lock.EnterUpgradeableReadLock();
|
||||
|
||||
if (_keyToIdMap.TryGetValue(key, out var id))
|
||||
return Get(itemType, id);
|
||||
|
||||
var type = CreatePublishedContentType(itemType, key);
|
||||
|
||||
try
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
_keyToIdMap[key] = type.Id;
|
||||
return _typesByAlias[GetAliasKey(type)] = _typesById[type.Id] = type;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_lock.IsWriteLockHeld)
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_lock.IsUpgradeableReadLockHeld)
|
||||
_lock.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a published content type.
|
||||
/// </summary>
|
||||
@@ -152,7 +190,8 @@ namespace Umbraco.Web.PublishedCache
|
||||
try
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
|
||||
if (type.TryGetKey(out var key))
|
||||
_keyToIdMap[key] = type.Id;
|
||||
return _typesByAlias[aliasKey] = _typesById[type.Id] = type;
|
||||
}
|
||||
finally
|
||||
@@ -188,7 +227,8 @@ namespace Umbraco.Web.PublishedCache
|
||||
try
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
|
||||
if (type.TryGetKey(out var key))
|
||||
_keyToIdMap[key] = type.Id;
|
||||
return _typesByAlias[GetAliasKey(type)] = _typesById[type.Id] = type;
|
||||
}
|
||||
finally
|
||||
@@ -204,27 +244,32 @@ namespace Umbraco.Web.PublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, Guid key)
|
||||
{
|
||||
IContentTypeComposition contentType = itemType switch
|
||||
{
|
||||
PublishedItemType.Content => _contentTypeService.Get(key),
|
||||
PublishedItemType.Media => _mediaTypeService.Get(key),
|
||||
PublishedItemType.Member => _memberTypeService.Get(key),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(itemType)),
|
||||
};
|
||||
if (contentType == null)
|
||||
throw new Exception($"ContentTypeService failed to find a {itemType.ToString().ToLower()} type with key \"{key}\".");
|
||||
|
||||
return _publishedContentTypeFactory.CreateContentType(contentType);
|
||||
}
|
||||
|
||||
private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, string alias)
|
||||
{
|
||||
if (GetPublishedContentTypeByAlias != null)
|
||||
return GetPublishedContentTypeByAlias(alias);
|
||||
|
||||
IContentTypeComposition contentType;
|
||||
switch (itemType)
|
||||
IContentTypeComposition contentType = itemType switch
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
contentType = _contentTypeService.Get(alias);
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
contentType = _mediaTypeService.Get(alias);
|
||||
break;
|
||||
case PublishedItemType.Member:
|
||||
contentType = _memberTypeService.Get(alias);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(itemType));
|
||||
}
|
||||
|
||||
PublishedItemType.Content => _contentTypeService.Get(alias),
|
||||
PublishedItemType.Media => _mediaTypeService.Get(alias),
|
||||
PublishedItemType.Member => _memberTypeService.Get(alias),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(itemType)),
|
||||
};
|
||||
if (contentType == null)
|
||||
throw new Exception($"ContentTypeService failed to find a {itemType.ToString().ToLower()} type with alias \"{alias}\".");
|
||||
|
||||
@@ -235,23 +280,13 @@ namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
if (GetPublishedContentTypeById != null)
|
||||
return GetPublishedContentTypeById(id);
|
||||
|
||||
IContentTypeComposition contentType;
|
||||
switch (itemType)
|
||||
IContentTypeComposition contentType = itemType switch
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
contentType = _contentTypeService.Get(id);
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
contentType = _mediaTypeService.Get(id);
|
||||
break;
|
||||
case PublishedItemType.Member:
|
||||
contentType = _memberTypeService.Get(id);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(itemType));
|
||||
}
|
||||
|
||||
PublishedItemType.Content => _contentTypeService.Get(id),
|
||||
PublishedItemType.Media => _mediaTypeService.Get(id),
|
||||
PublishedItemType.Member => _memberTypeService.Get(id),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(itemType)),
|
||||
};
|
||||
if (contentType == null)
|
||||
throw new Exception($"ContentTypeService failed to find a {itemType.ToString().ToLower()} type with id {id}.");
|
||||
|
||||
@@ -259,6 +294,7 @@ namespace Umbraco.Web.PublishedCache
|
||||
}
|
||||
|
||||
// for unit tests - changing the callback must reset the cache obviously
|
||||
// TODO: Why does this even exist? For testing you'd pass in a mocked service to get by id
|
||||
private Func<string, IPublishedContentType> _getPublishedContentTypeByAlias;
|
||||
internal Func<string, IPublishedContentType> GetPublishedContentTypeByAlias
|
||||
{
|
||||
@@ -282,6 +318,7 @@ namespace Umbraco.Web.PublishedCache
|
||||
}
|
||||
|
||||
// for unit tests - changing the callback must reset the cache obviously
|
||||
// TODO: Why does this even exist? For testing you'd pass in a mocked service to get by id
|
||||
private Func<int, IPublishedContentType> _getPublishedContentTypeById;
|
||||
internal Func<int, IPublishedContentType> GetPublishedContentTypeById
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user