Merge branch 'temp8-U4-11227' into temp8-U4-11282

# Conflicts:
#	src/Umbraco.Core/Models/ContentBase.cs
#	src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
#	src/Umbraco.Tests/Services/EntityServiceTests.cs
#	src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs
#	src/Umbraco.Web/PublishedContentExtensions.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
This commit is contained in:
Shannon
2018-05-08 12:31:03 +10:00
144 changed files with 2598 additions and 1700 deletions

View File

@@ -3,22 +3,22 @@
namespace Umbraco.Web.PublishedCache
{
/// <summary>
/// Provides the default implementation of <see cref="ISystemDefaultCultureProvider"/>.
/// Provides the default implementation of <see cref="IDefaultCultureAccessor"/>.
/// </summary>
public class SystemDefaultCultureProvider : ISystemDefaultCultureProvider
public class DefaultCultureAccessor : IDefaultCultureAccessor
{
private readonly ILocalizationService _localizationService;
/// <summary>
/// Initializes a new instance of the <see cref="SystemDefaultCultureProvider"/> class.
/// Initializes a new instance of the <see cref="DefaultCultureAccessor"/> class.
/// </summary>
/// <param name="localizationService"></param>
public SystemDefaultCultureProvider(ILocalizationService localizationService)
public DefaultCultureAccessor(ILocalizationService localizationService)
{
_localizationService = localizationService;
}
/// <inheritdoc />
public string DefaultCulture => _localizationService.GetDefaultLanguageIsoCode(); // capture - fast
public string DefaultCulture => _localizationService.GetDefaultLanguageIsoCode() ?? ""; // fast
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Umbraco.Web.PublishedCache
{
/// <summary>
/// Gives access to the default culture.
/// </summary>
public interface IDefaultCultureAccessor
{
/// <summary>
/// Gets the system default culture.
/// </summary>
/// <remarks>
/// <para>Implementations must NOT return a null value. Return an empty string for the invariant culture.</para>
/// </remarks>
string DefaultCulture { get; }
}
}

View File

@@ -33,11 +33,18 @@ namespace Umbraco.Web.PublishedCache
/// <summary>
/// Gets the snapshot-level cache.
/// </summary>
/// <remarks>
/// <para>The snapshot-level cache belongs to this snapshot only.</para>
/// </remarks>
ICacheProvider SnapshotCache { get; }
/// <summary>
/// Gets the elements-level cache.
/// </summary>
/// <remarks>
/// <para>The elements-level cache is shared by all snapshots relying on the same elements,
/// ie all snapshots built on top of unchanging content / media / etc.</para>
/// </remarks>
ICacheProvider ElementsCache { get; }
/// <summary>

View File

@@ -1,13 +0,0 @@
namespace Umbraco.Web.PublishedCache
{
/// <summary>
/// Provides the system default culture.
/// </summary>
public interface ISystemDefaultCultureProvider
{
/// <summary>
/// Gets the system default culture.
/// </summary>
string DefaultCulture { get; }
}
}

View File

@@ -43,11 +43,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
return "NuCache.Profile.Name[" + userId + "]";
}
public static string PropertyRecurse(Guid contentUid, string typeAlias, bool previewing)
{
return "NuCache.Property.Recurse[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]";
}
public static string PropertyCacheValues(Guid contentUid, string typeAlias, bool previewing)
{
return "NuCache.Property.CacheValues[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]";

View File

@@ -104,8 +104,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
// hideTopLevelNode = support legacy stuff, look for /*/path/to/node
// else normal, look for /path/to/node
content = hideTopLevelNode.Value
? GetAtRoot(preview).SelectMany(x => x.Children).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0])
: GetAtRoot(preview).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0]);
? GetAtRoot(preview).SelectMany(x => x.Children).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0])
: GetAtRoot(preview).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0]);
content = FollowRoute(content, parts, 1, culture);
}
@@ -114,7 +114,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// have to look for /foo (see note in ApplyHideTopLevelNodeFromPath).
if (content == null && hideTopLevelNode.Value && parts.Length == 1)
{
content = GetAtRoot(preview).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0]);
content = GetAtRoot(preview).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0]);
}
return content;
@@ -147,14 +147,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
var hasDomains = _domainHelper.NodeHasDomains(n.Id);
while (hasDomains == false && n != null) // n is null at root
{
var urlName = n.GetUrlName(_localizationService, culture);
if (urlName == null)
var varies = n.ContentType.Variations.Has(ContentVariation.CultureNeutral);
var urlSegment = varies ? n.GetCulture(culture)?.UrlSegment : n.UrlSegment;
if (urlSegment.IsNullOrWhiteSpace())
{
//we cannot continue, it will be null if the item is not published
return null;
}
//// at that point we should have an urlSegment, unless something weird is happening
//// at content level, such as n.GetCulture() returning null for some (weird) reason,
//// and then what? fallback to the invariant segment... far from perfect but eh...
//if (string.IsNullOrWhiteSpace(urlSegment)) urlSegment = n.UrlSegment;
pathParts.Add(urlName);
pathParts.Add(urlSegment);
// move to parent node
n = n.Parent;
@@ -183,8 +189,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
var part = parts[i++];
content = content.Children.FirstOrDefault(x =>
{
var urlName = x.GetUrlName(_localizationService, culture);
return urlName == part;
var urlSegment = x.GetCulture(culture).UrlSegment;
return urlSegment == part;
});
}
return content;

View File

@@ -33,10 +33,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
int parentContentId,
DateTime createDate, int creatorId,
ContentData draftData, ContentData publishedData,
IPublishedSnapshotAccessor publishedSnapshotAccessor)
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor)
: this(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId)
{
SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor);
SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor);
}
// 2-phases ctor, phase 1
@@ -58,7 +59,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// two-phase ctor, phase 2
public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
ContentType = contentType;
@@ -66,9 +67,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
throw new ArgumentException("Both draftData and publishedData cannot be null at the same time.");
if (draftData != null)
Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor).CreateModel();
Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
if (publishedData != null)
Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor).CreateModel();
Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
}
// clone parent
@@ -97,7 +98,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// clone with new content type
public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
Id = origin.Id;
Uid = origin.Uid;
@@ -112,8 +113,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor).CreateModel();
Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
ChildContentIds = origin.ChildContentIds; // can be the *same* list FIXME oh really?
}

View File

@@ -17,9 +17,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 };
public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
Node.SetContentTypeAndData(contentType, DraftData, PublishedData, publishedSnapshotAccessor);
Node.SetContentTypeAndData(contentType, DraftData, PublishedData, publishedSnapshotAccessor, variationContextAccessor);
}
}
}

View File

@@ -19,6 +19,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// SnapDictionary has unit tests to ensure it all works correctly
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly ConcurrentDictionary<int, LinkedNode<ContentNode>> _contentNodes;
private readonly ConcurrentDictionary<int, LinkedNode<object>> _contentRootNodes;
private readonly ConcurrentDictionary<int, LinkedNode<PublishedContentType>> _contentTypesById;
@@ -43,9 +44,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Ctor
public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, BPlusTree<int, ContentNodeKit> localDb = null)
public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree<int, ContentNodeKit> localDb = null)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_variationContextAccessor = variationContextAccessor;
_logger = logger;
_localDb = localDb;
@@ -277,7 +279,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (node == null) continue;
var contentTypeId = node.ContentType.Id;
if (index.TryGetValue(contentTypeId, out PublishedContentType contentType) == false) continue;
SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor));
SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor));
}
}
finally
@@ -391,7 +393,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentNodes.TryGetValue(id, out LinkedNode<ContentNode> link);
if (link?.Value == null)
continue;
var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor);
var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor);
SetValueLocked(_contentNodes, id, node);
if (_localDb != null) RegisterChange(id, node.ToKit());
}
@@ -414,7 +416,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return false;
// and use
kit.Build(link.Value, _publishedSnapshotAccessor);
kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor);
return true;
}

View File

@@ -9,16 +9,16 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
public IReadOnlyDictionary<string, CultureVariation> ReadFrom(Stream stream)
{
var dict = new Dictionary<string, CultureVariation>();
// read variations count
var pcount = PrimitiveSerializer.Int32.ReadFrom(stream);
if (pcount == 0) return Empty;
// read each variation
var dict = new Dictionary<string, CultureVariation>();
for (var i = 0; i < pcount; i++)
{
var languageId = PrimitiveSerializer.String.ReadFrom(stream);
var cultureVariation = new CultureVariation { Name = ReadStringObject(stream) };
var cultureVariation = new CultureVariation { Name = ReadStringObject(stream), Date = ReadDateTime(stream) };
dict[languageId] = cultureVariation;
}
return dict;
@@ -40,6 +40,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
PrimitiveSerializer.String.WriteTo(culture, stream); // should never be null
WriteObject(variation.Name, stream); // write an object in case it's null (though... should not happen)
PrimitiveSerializer.DateTime.WriteTo(variation.Date, stream);
}
}
}

View File

@@ -6,20 +6,18 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
// represents everything that is specific to edited or published version
internal class ContentData
{
public string Name { get; set; }
public int VersionId { get; set; }
public DateTime VersionDate { get; set; }
public int WriterId { get; set; }
public int TemplateId { get; set; }
public bool Published { get; set; }
public IDictionary<string, PropertyData[]> Properties { get; set; }
/// <summary>
/// The collection of language Id to name for the content item
/// </summary>
public IReadOnlyDictionary<string, CultureVariation> CultureInfos { get; set; }
public string Name { get; set; }
public int VersionId { get; set; }
//TODO: This will not make a lot of sense since we'll have dates for each variant publishing, need to wait on Stephane
public DateTime VersionDate { get; set; }
public int WriterId { get; set; }
public int TemplateId { get; set; }
public IDictionary<string, PropertyData[]> Properties { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System;
using Newtonsoft.Json;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
@@ -10,6 +11,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
[JsonProperty("name")]
public string Name { get; set; }
//TODO: We may want some date stamps here
[JsonProperty("date")]
public DateTime Date { get; set; }
}
}

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
// fixme - use SqlTemplate for these queries else it's going to be horribly slow!
// provides efficient database access for NuCache
internal class Database
internal class DatabaseDataSource : IDataSource
{
// we want arrays, we want them all loaded, not an enumerable
@@ -186,7 +186,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
if (Debugger.IsAttached)
throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding.");
Current.Logger.Warn<Database>("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding.");
Current.Logger.Warn<DatabaseDataSource>("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding.");
}
else
{
@@ -211,7 +211,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
if (Debugger.IsAttached)
throw new Exception("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding.");
Current.Logger.Warn<Database>("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding.");
Current.Logger.Warn<DatabaseDataSource>("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding.");
}
else
{

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using Umbraco.Core.Scoping;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
/// <summary>
/// Defines a data source for NuCache.
/// </summary>
internal interface IDataSource
{
ContentNodeKit GetContentSource(IScope scope, int id);
IEnumerable<ContentNodeKit> GetAllContentSources(IScope scope);
IEnumerable<ContentNodeKit> GetBranchContentSources(IScope scope, int id);
IEnumerable<ContentNodeKit> GetTypeContentSources(IScope scope, IEnumerable<int> ids);
ContentNodeKit GetMediaSource(IScope scope, int id);
IEnumerable<ContentNodeKit> GetAllMediaSources(IScope scope);
IEnumerable<ContentNodeKit> GetBranchMediaSources(IScope scope, int id);
IEnumerable<ContentNodeKit> GetTypeMediaSources(IScope scope, IEnumerable<int> ids);
}
}

View File

@@ -1,14 +1,26 @@
using Newtonsoft.Json;
using System;
using Newtonsoft.Json;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
internal class PropertyData
{
private string _culture;
private string _segment;
[JsonProperty("culture")]
public string Culture { get; set; }
public string Culture
{
get => _culture;
set => _culture = value ?? throw new ArgumentNullException(nameof(value));
}
[JsonProperty("seg")]
public string Segment { get; set; }
public string Segment
{
get => _segment;
set => _segment = value ?? throw new ArgumentNullException(nameof(value));
}
[JsonProperty("val")]
public object Value { get; set; }

View File

@@ -16,6 +16,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
class MemberCache : IPublishedMemberCache, INavigableData
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
public readonly IVariationContextAccessor VariationContextAccessor;
private readonly ICacheProvider _snapshotCache;
private readonly IMemberService _memberService;
private readonly IDataTypeService _dataTypeService;
@@ -23,10 +24,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly PublishedContentTypeCache _contentTypeCache;
private readonly bool _previewDefault;
public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, IDataTypeService dataTypeService, ILocalizationService localizationService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, IDataTypeService dataTypeService, ILocalizationService localizationService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
_snapshotCache = snapshotCache;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
_memberService = memberService;
_dataTypeService = dataTypeService;
_localizationService = localizationService;
@@ -63,14 +65,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
var member = _memberService.GetById(memberId);
return member == null
? null
: PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor);
: PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
});
}
private IPublishedContent /*IPublishedMember*/ GetById(IMember member, bool previewing)
{
return GetCacheItem(CacheKeys.MemberCacheMember("ById", _previewDefault, member.Id), () =>
PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor));
PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor));
}
public IPublishedContent /*IPublishedMember*/ GetByProviderKey(object key)
@@ -105,7 +107,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public IPublishedContent /*IPublishedMember*/ GetByMember(IMember member)
{
return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor);
return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
}
public IEnumerable<IPublishedContent> GetAtRoot(bool preview)
@@ -113,7 +115,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// because members are flat (not a tree) everything is at root
// because we're loading everything... let's just not cache?
var members = _memberService.GetAllMembers();
return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor));
return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor));
}
public XPathNavigator CreateNavigator()

View File

@@ -28,7 +28,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.Navigable
XmlString(i++, _content.TemplateId),
XmlString(i++, _content.WriterId),
XmlString(i++, _content.CreatorId),
XmlString(i++, _content.UrlName),
XmlString(i++, _content.UrlSegment),
XmlString(i, _content.IsDraft)
};
}

View File

@@ -1,11 +1,5 @@
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using LightInject;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Components;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
namespace Umbraco.Web.PublishedCache.NuCache
{
@@ -15,6 +9,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
base.Compose(composition);
// register the NuCache database data source
composition.Container.Register<IDataSource, DatabaseDataSource>();
// register the NuCache published snapshot service
// must register default options, required in the service ctor
composition.Container.Register(factory => new PublishedSnapshotService.Options());

View File

@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Collections;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
@@ -18,7 +19,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly Guid _contentUid;
private readonly bool _isPreviewing;
private readonly bool _isMember;
private readonly IPublishedContent _content;
private readonly PublishedContent _content;
private readonly ContentVariation _variations;
private readonly object _locko = new object();
@@ -34,7 +36,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
private CacheValues _cacheValues;
private string _valuesCacheKey;
private string _recurseCacheKey;
// initializes a published content property with no value
public Property(PublishedPropertyType propertyType, PublishedContent content, IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Element)
@@ -49,7 +50,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
foreach (var sourceValue in sourceValues)
{
if (sourceValue.Culture == null && sourceValue.Segment == null)
if (sourceValue.Culture == "" && sourceValue.Segment == "")
{
_sourceValue = sourceValue.Value;
}
@@ -68,10 +69,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
_isPreviewing = content.IsPreviewing;
_isMember = content.ContentType.ItemType == PublishedItemType.Member;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_variations = propertyType.Variations;
}
// clone for previewing as draft a published content that is published and has no draft
public Property(Property origin, IPublishedContent content)
public Property(Property origin, PublishedContent content)
: base(origin.PropertyType, origin.ReferenceCacheLevel)
{
_sourceValue = origin._sourceValue;
@@ -82,15 +84,12 @@ namespace Umbraco.Web.PublishedCache.NuCache
_isPreviewing = true;
_isMember = origin._isMember;
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
_variations = origin._variations;
}
public override bool HasValue(string culture = null, string segment = null) => _sourceValue != null
&& (!(_sourceValue is string) || string.IsNullOrWhiteSpace((string) _sourceValue) == false);
// used to cache the recursive *property* for this property
internal string RecurseCacheKey => _recurseCacheKey
?? (_recurseCacheKey = CacheKeys.PropertyRecurse(_contentUid, Alias, _isPreviewing));
// used to cache the CacheValues of this property
internal string ValuesCacheKey => _valuesCacheKey
?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(_contentUid, Alias, _isPreviewing));
@@ -145,7 +144,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// this is always invoked from within a lock, so does not require its own lock
private object GetInterValue(string culture, string segment)
{
if (culture == null && segment == null)
if (culture == "" && segment == "")
{
if (_interInitialized) return _interValue;
_interValue = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing);
@@ -158,7 +157,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var k = new CompositeStringStringKey(culture, segment);
if (!_sourceValues.TryGetValue(k, out var vvalue))
_sourceValues[k] = vvalue = new SourceInterValue { Culture = culture, Segment = segment };
_sourceValues[k] = vvalue = new SourceInterValue { Culture = culture, Segment = segment, SourceValue = GetSourceValue(culture, segment) };
if (vvalue.InterInitialized) return vvalue.InterValue;
vvalue.InterValue = PropertyType.ConvertSourceToInter(_content, vvalue.SourceValue, _isPreviewing);
@@ -168,7 +167,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override object GetSourceValue(string culture = null, string segment = null)
{
if (culture == null && segment == null)
ContextualizeVariation(ref culture, ref segment);
if (culture == "" && segment == "")
return _sourceValue;
lock (_locko)
@@ -178,8 +179,22 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
private void ContextualizeVariation(ref string culture, ref string segment)
{
if (culture != null && segment != null) return;
// use context values
// fixme CultureSegment?
var publishedVariationContext = _content.VariationContextAccessor?.VariationContext;
if (culture == null) culture = _variations.Has(ContentVariation.CultureNeutral) ? publishedVariationContext?.Culture : "";
if (segment == null) segment = _variations.Has(ContentVariation.CultureNeutral) ? publishedVariationContext?.Segment : "";
}
public override object GetValue(string culture = null, string segment = null)
{
ContextualizeVariation(ref culture, ref segment);
object value;
lock (_locko)
{
var cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
@@ -190,12 +205,16 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(_content, initialCacheLevel, GetInterValue(culture, segment), _isPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
value = cacheValues.ObjectValue;
}
return value;
}
public override object GetXPathValue(string culture = null, string segment = null)
{
ContextualizeVariation(ref culture, ref segment);
lock (_locko)
{
var cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
@@ -227,7 +246,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// this is always invoked from within a lock, so does not require its own lock
public CacheValue For(string culture, string segment)
{
if (culture == null && segment == null)
if (culture == "" && segment == "")
return this;
if (_values == null)

View File

@@ -18,18 +18,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
// ReSharper disable once InconsistentNaming
internal readonly ContentData _contentData; // internal for ContentNode cloning
private readonly string _urlName;
private IReadOnlyDictionary<string, PublishedCultureName> _cultureNames;
private readonly string _urlSegment;
#region Constructors
public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
_contentNode = contentNode;
_contentData = contentData;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
_urlName = _contentData.Name.ToUrlSegment();
_urlSegment = _contentData.Name.ToUrlSegment();
IsPreviewing = _contentData.Published == false;
var properties = new List<IPublishedProperty>();
@@ -70,9 +70,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
_contentNode = contentNode;
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
_contentData = origin._contentData;
_urlName = origin._urlName;
_urlSegment = origin._urlSegment;
IsPreviewing = origin.IsPreviewing;
// here is the main benefit: we do not re-create properties so if anything
@@ -85,10 +86,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
private PublishedContent(PublishedContent origin)
{
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
_contentNode = origin._contentNode;
_contentData = origin._contentData;
_urlName = origin._urlName;
_urlSegment = origin._urlSegment;
IsPreviewing = true;
// clone properties so _isPreviewing is true
@@ -152,51 +154,133 @@ namespace Umbraco.Web.PublishedCache.NuCache
#endregion
#region IPublishedContent
#region Content Type
public override int Id => _contentNode.Id;
/// <inheritdoc />
public override PublishedContentType ContentType => _contentNode.ContentType;
#endregion
#region PublishedElement
/// <inheritdoc />
public override Guid Key => _contentNode.Uid;
public override int DocumentTypeId => _contentNode.ContentType.Id;
public override string DocumentTypeAlias => _contentNode.ContentType.Alias;
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
public override string Name => _contentData.Name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames
#endregion
#region PublishedContent
/// <inheritdoc />
public override int Id => _contentNode.Id;
/// <inheritdoc />
public override string Name
{
get
{
if (!ContentType.Variations.HasFlag(ContentVariation.CultureNeutral))
return null;
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return _contentData.Name;
if (_cultureNames == null)
{
var d = new Dictionary<string, PublishedCultureName>(StringComparer.InvariantCultureIgnoreCase);
foreach(var c in _contentData.CultureInfos)
{
d[c.Key] = new PublishedCultureName(c.Value.Name, c.Value.Name.ToUrlSegment());
}
_cultureNames = d;
}
return _cultureNames;
var culture = VariationContextAccessor.VariationContext.Culture;
if (culture == "")
return _contentData.Name;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.Name : null;
}
}
public override int Level => _contentNode.Level;
public override string Path => _contentNode.Path;
/// <inheritdoc />
public override string UrlSegment
{
get
{
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return _urlSegment;
var culture = VariationContextAccessor.VariationContext.Culture;
if (culture == "")
return _urlSegment;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.UrlSegment : null;
}
}
/// <inheritdoc />
public override int SortOrder => _contentNode.SortOrder;
/// <inheritdoc />
public override int Level => _contentNode.Level;
/// <inheritdoc />
public override string Path => _contentNode.Path;
/// <inheritdoc />
public override int TemplateId => _contentData.TemplateId;
public override string UrlName => _urlName;
public override DateTime CreateDate => _contentNode.CreateDate;
public override DateTime UpdateDate => _contentData.VersionDate;
/// <inheritdoc />
public override int CreatorId => _contentNode.CreatorId;
/// <inheritdoc />
public override string CreatorName => GetProfileNameById(_contentNode.CreatorId);
/// <inheritdoc />
public override DateTime CreateDate => _contentNode.CreateDate;
/// <inheritdoc />
public override int WriterId => _contentData.WriterId;
/// <inheritdoc />
public override string WriterName => GetProfileNameById(_contentData.WriterId);
/// <inheritdoc />
public override DateTime UpdateDate => _contentData.VersionDate;
private IReadOnlyDictionary<string, PublishedCultureInfos> _cultureInfos;
private static readonly IReadOnlyDictionary<string, PublishedCultureInfos> NoCultureInfos = new Dictionary<string, PublishedCultureInfos>();
/// <inheritdoc />
public override PublishedCultureInfos GetCulture(string culture = null)
{
// handle context culture
if (culture == null)
culture = VariationContextAccessor.VariationContext.Culture;
// no invariant culture infos
if (culture == "") return null;
// get
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos : null;
}
/// <inheritdoc />
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures
{
get
{
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return NoCultureInfos;
if (_cultureInfos != null) return _cultureInfos;
if (_contentData.CultureInfos == null)
throw new Exception("oops: _contentDate.CultureInfos is null.");
return _cultureInfos = _contentData.CultureInfos
.ToDictionary(x => x.Key, x => new PublishedCultureInfos(x.Key, x.Value.Name, x.Value.Date));
}
}
/// <inheritdoc />
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
/// <inheritdoc />
public override bool IsDraft => _contentData.Published == false;
#endregion
#region Tree
/// <inheritdoc />
public override IPublishedContent Parent
{
get
@@ -215,10 +299,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
private string _childrenCacheKey;
private string ChildrenCacheKey => _childrenCacheKey ?? (_childrenCacheKey = CacheKeys.PublishedContentChildren(Key, IsPreviewing));
/// <inheritdoc />
public override IEnumerable<IPublishedContent> Children
{
get
@@ -232,6 +313,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
private string _childrenCacheKey;
private string ChildrenCacheKey => _childrenCacheKey ?? (_childrenCacheKey = CacheKeys.PublishedContentChildren(Key, IsPreviewing));
private IEnumerable<IPublishedContent> GetChildren()
{
IEnumerable<IPublishedContent> c;
@@ -255,8 +340,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
// Q: perfs-wise, is it better than having the store managed an ordered list
}
#endregion
#region Properties
/// <inheritdoc cref="IPublishedElement.Properties"/>
public override IEnumerable<IPublishedProperty> Properties => PropertiesArray;
/// <inheritdoc cref="IPublishedElement.GetProperty(string)"/>
public override IPublishedProperty GetProperty(string alias)
{
var index = _contentNode.ContentType.GetPropertyIndex(alias);
@@ -267,21 +359,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
return property;
}
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
var property = GetProperty(alias);
if (recurse == false) return property;
var cache = GetAppropriateCache();
if (cache == null)
return base.GetProperty(alias, true);
var key = ((Property)property).RecurseCacheKey;
return (Property)cache.GetCacheItem(key, () => base.GetProperty(alias, true));
}
public override PublishedContentType ContentType => _contentNode.ContentType;
#endregion
#region Caching
@@ -308,6 +385,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Internal
// used by property
internal IVariationContextAccessor VariationContextAccessor { get; }
// used by navigable content
internal IPublishedProperty[] PropertiesArray { get; }

View File

@@ -15,13 +15,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
private readonly IMember _member;
private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor)
: base(contentNode, contentData, publishedSnapshotAccessor)
private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
: base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor)
{
_member = member;
}
public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor)
public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
var d = new ContentData
{
@@ -37,7 +37,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
member.Level, member.Path, member.SortOrder,
member.ParentId,
member.CreateDate, member.CreatorId);
return new PublishedMember(member, n, d, publishedSnapshotAccessor).CreateModel();
return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
}
private static Dictionary<string, PropertyData[]> GetPropertyValues(PublishedContentType contentType, IMember member)

View File

@@ -17,7 +17,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
_service = service;
_defaultPreview = defaultPreview;
SnapshotCache = new ObjectCacheRuntimeCacheProvider();
}
public class PublishedSnapshotElements : IDisposable
@@ -49,7 +48,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Caches
public ICacheProvider SnapshotCache { get; }
public ICacheProvider SnapshotCache => Elements.SnapshotCache;
public ICacheProvider ElementsCache => Elements.ElementsCache;

View File

@@ -28,7 +28,6 @@ using Umbraco.Web.Install;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
using Umbraco.Web.PublishedCache.XmlPublishedCache;
using Umbraco.Web.Routing;
using Database = Umbraco.Web.PublishedCache.NuCache.DataSource.Database;
namespace Umbraco.Web.PublishedCache.NuCache
{
@@ -37,14 +36,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly ServiceContext _serviceContext;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
private readonly IScopeProvider _scopeProvider;
private readonly Database _dataSource;
private readonly IDataSource _dataSource;
private readonly ILogger _logger;
private readonly IDocumentRepository _documentRepository;
private readonly IMediaRepository _mediaRepository;
private readonly IMemberRepository _memberRepository;
private readonly IGlobalSettings _globalSettings;
private readonly ISiteDomainHelper _siteDomainHelper;
private readonly ISystemDefaultCultureProvider _systemDefaultCultureProvider;
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
// volatile because we read it with no lock
private volatile bool _isReady;
@@ -82,24 +81,25 @@ namespace Umbraco.Web.PublishedCache.NuCache
public PublishedSnapshotService(Options options, MainDom mainDom, IRuntimeState runtime,
ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap,
IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, IScopeProvider scopeProvider,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
ILogger logger, IScopeProvider scopeProvider,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
ISystemDefaultCultureProvider systemDefaultCultureProvider,
IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper)
: base(publishedSnapshotAccessor)
IDefaultCultureAccessor defaultCultureAccessor,
IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper)
: base(publishedSnapshotAccessor, variationContextAccessor)
{
//if (Interlocked.Increment(ref _singletonCheck) > 1)
// throw new Exception("Singleton must be instancianted only once!");
_serviceContext = serviceContext;
_publishedContentTypeFactory = publishedContentTypeFactory;
_dataSource = new Database();
_dataSource = dataSource;
_logger = logger;
_scopeProvider = scopeProvider;
_documentRepository = documentRepository;
_mediaRepository = mediaRepository;
_memberRepository = memberRepository;
_systemDefaultCultureProvider = systemDefaultCultureProvider;
_defaultCultureAccessor = defaultCultureAccessor;
_globalSettings = globalSettings;
_siteDomainHelper = siteDomainHelper;
@@ -145,13 +145,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
// stores are created with a db so they can write to it, but they do not read from it,
// stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to
// figure out whether it can read the dbs or it should populate them from sql
_contentStore = new ContentStore(publishedSnapshotAccessor, logger, _localContentDb);
_mediaStore = new ContentStore(publishedSnapshotAccessor, logger, _localMediaDb);
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb);
}
else
{
_contentStore = new ContentStore(publishedSnapshotAccessor, logger);
_mediaStore = new ContentStore(publishedSnapshotAccessor, logger);
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
}
_domainStore = new SnapDictionary<int, Domain>();
@@ -173,7 +173,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
try
{
if (_localDbExists) // fixme?
if (_localDbExists)
{
LockAndLoadContent(LoadContentFromLocalDbLocked);
LockAndLoadMedia(LoadMediaFromLocalDbLocked);
@@ -333,7 +333,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
//private void LoadContent(IContent content)
//{
// var contentService = _serviceContext.ContentService as ContentService;
// if (contentService == null) throw new Exception("oops");
// var newest = content;
// var published = newest.Published
// ? newest
@@ -536,7 +535,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
if (draftChanged || publishedChanged)
((PublishedSnapshot)CurrentPublishedSnapshot).Resync();
((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync();
}
private void NotifyLocked(IEnumerable<ContentCacheRefresher.JsonPayload> payloads, out bool draftChanged, out bool publishedChanged)
@@ -544,9 +543,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
publishedChanged = false;
draftChanged = false;
if (!(_serviceContext.ContentService is ContentService))
throw new Exception("oops");
// locks:
// content (and content types) are read-locked while reading content
// contentStore is wlocked (so readable, only no new views)
@@ -633,16 +629,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
if (anythingChanged)
((PublishedSnapshot)CurrentPublishedSnapshot).Resync();
((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync();
}
private void NotifyLocked(IEnumerable<MediaCacheRefresher.JsonPayload> payloads, out bool anythingChanged)
{
anythingChanged = false;
if (!(_serviceContext.MediaService is MediaService))
throw new Exception("oops");
// locks:
// see notes for content cache refresher
@@ -722,7 +715,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
Notify<IContentType>(_contentStore, payloads, RefreshContentTypesLocked);
Notify<IMediaType>(_mediaStore, payloads, RefreshMediaTypesLocked);
((PublishedSnapshot)CurrentPublishedSnapshot).Resync();
((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync();
}
private void Notify<T>(ContentStore store, ContentTypeCacheRefresher.JsonPayload[] payloads, Action<IEnumerable<int>, IEnumerable<int>, IEnumerable<int>, IEnumerable<int>> action)
@@ -778,9 +771,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
// some locking on datatypes
_publishedContentTypeFactory.NotifyDataTypeChanges(idsA);
if (!(_serviceContext.ContentService is ContentService))
throw new Exception("oops");
using (var scope = _scopeProvider.CreateScope())
{
scope.ReadLock(Constants.Locks.ContentTree);
@@ -788,9 +778,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
scope.Complete();
}
if (!(_serviceContext.MediaService is MediaService))
throw new Exception("oops");
using (var scope = _scopeProvider.CreateScope())
{
scope.ReadLock(Constants.Locks.MediaTree);
@@ -799,7 +786,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
((PublishedSnapshot)CurrentPublishedSnapshot).Resync();
((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync();
}
public override void Notify(DomainCacheRefresher.JsonPayload[] payloads)
@@ -897,9 +884,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
// contentStore is wlocked (so readable, only no new views)
// and it can be wlocked by 1 thread only at a time
if (!(_serviceContext.ContentService is ContentService))
throw new Exception("oops");
var refreshedIdsA = refreshedIds.ToArray();
using (var scope = _scopeProvider.CreateScope())
@@ -921,9 +905,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
// mediaStore is wlocked (so readable, only no new views)
// and it can be wlocked by 1 thread only at a time
if (!(_serviceContext.MediaService is MediaService))
throw new Exception("oops");
var refreshedIdsA = refreshedIds.ToArray();
using (var scope = _scopeProvider.CreateScope())
@@ -955,6 +936,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
return new PublishedSnapshot(this, preview);
}
// gets a new set of elements
// always creates a new set of elements,
// even though the underlying elements may not change (store snapshots)
public PublishedSnapshot.PublishedSnapshotElements GetElements(bool previewDefault)
{
// note: using ObjectCacheRuntimeCacheProvider for elements and snapshot caches
@@ -996,7 +980,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// a MaxValue to make sure this one runs last, and it should be ok
scopeContext.Enlist("Umbraco.Web.PublishedCache.NuCache.PublishedSnapshotService.Resync", () => this, (completed, svc) =>
{
((PublishedSnapshot)svc.CurrentPublishedSnapshot).Resync();
((PublishedSnapshot)svc.CurrentPublishedSnapshot)?.Resync();
}, int.MaxValue);
}
@@ -1014,7 +998,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _logger);
var defaultCulture = _systemDefaultCultureProvider.DefaultCulture;
var defaultCulture = _defaultCultureAccessor.DefaultCulture;
var domainCache = new DomainCache(domainSnap, defaultCulture);
var domainHelper = new DomainHelper(domainCache, _siteDomainHelper);
@@ -1022,7 +1006,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService),
MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache),
MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, _serviceContext.DataTypeService, _serviceContext.LocalizationService, memberTypeCache, PublishedSnapshotAccessor),
MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, _serviceContext.DataTypeService, _serviceContext.LocalizationService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor),
DomainCache = domainCache,
SnapshotCache = snapshotCache,
ElementsCache = elementsCache
@@ -1080,21 +1064,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
db.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id", new { id = item.Id });
}
private static readonly string[] PropertiesImpactingAllVersions = { "SortOrder", "ParentId", "Level", "Path", "Trashed" };
private static bool HasChangesImpactingAllVersions(IContent icontent)
{
var content = (Content)icontent;
// UpdateDate will be dirty
// Published may be dirty if saving a Published entity
// so cannot do this (would always be true):
//return content.IsEntityDirty();
// have to be more precise & specify properties
return PropertiesImpactingAllVersions.Any(content.IsPropertyDirty);
}
private void OnContentRefreshedEntity(DocumentRepository sender, DocumentRepository.ScopedEntityEventArgs args)
{
var db = args.Scope.Database;
@@ -1216,7 +1185,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
var cultureData = new Dictionary<string, CultureVariation>();
// fixme refactor!!!
var names = content is IContent document
? (published
? document.PublishNames
@@ -1225,7 +1193,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
foreach (var (culture, name) in names)
{
cultureData[culture] = new CultureVariation { Name = name };
cultureData[culture] = new CultureVariation { Name = name, Date = content.GetCultureDate(culture) };
}
//the dictionary that will be serialized

View File

@@ -87,15 +87,6 @@ namespace Umbraco.Web.PublishedCache
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
if (recurse)
{
throw new NotSupportedException();
}
return GetProperty(alias);
}
public override IPublishedProperty GetProperty(string alias)
{
return _properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
@@ -144,13 +135,11 @@ namespace Umbraco.Web.PublishedCache
public override string Name => _member.Name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override PublishedCultureInfos GetCulture(string culture = null) => throw new NotSupportedException();
public override string UrlName => throw new NotSupportedException();
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string DocumentTypeAlias => _member.ContentTypeAlias;
public override int DocumentTypeId => _member.ContentType.Id;
public override string UrlSegment => throw new NotSupportedException();
//TODO: ARGH! need to fix this - this is not good because it uses ApplicationContext.Current
public override string WriterName => _member.GetCreatorProfile().Name;

View File

@@ -1,17 +1,20 @@
using System.Collections.Generic;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Cache;
namespace Umbraco.Web.PublishedCache
{
abstract class PublishedSnapshotServiceBase : IPublishedSnapshotService
{
protected PublishedSnapshotServiceBase(IPublishedSnapshotAccessor publishedSnapshotAccessor)
protected PublishedSnapshotServiceBase(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
{
PublishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
}
public IPublishedSnapshotAccessor PublishedSnapshotAccessor { get; }
public IVariationContextAccessor VariationContextAccessor { get; }
// note: NOT setting _publishedSnapshotAccessor.PublishedSnapshot here because it is the
// responsibility of the caller to manage what the 'current' facade is

View File

@@ -0,0 +1,225 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.XPath;
using Examine.LuceneEngine.Providers;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
/// <summary>
/// An IPublishedContent that is represented all by a dictionary.
/// </summary>
/// <remarks>
/// This is a helper class and definitely not intended for public use, it expects that all of the values required
/// to create an IPublishedContent exist in the dictionary by specific aliases.
/// </remarks>
internal class DictionaryPublishedContent : PublishedContentBase
{
// note: I'm not sure this class fully complies with IPublishedContent rules especially
// I'm not sure that _properties contains all properties including those without a value,
// neither that GetProperty will return a property without a value vs. null... @zpqrtbnk
// List of properties that will appear in the XML and do not match
// anything in the ContentType, so they must be ignored.
private static readonly string[] IgnoredKeys = { "version", "isDoc" };
public DictionaryPublishedContent(
IReadOnlyDictionary<string, string> valueDictionary,
Func<int, IPublishedContent> getParent,
Func<int, XPathNavigator, IEnumerable<IPublishedContent>> getChildren,
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
ICacheProvider cacheProvider,
PublishedContentTypeCache contentTypeCache,
XPathNavigator nav,
bool fromExamine)
{
if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary));
if (getParent == null) throw new ArgumentNullException(nameof(getParent));
if (getProperty == null) throw new ArgumentNullException(nameof(getProperty));
_getParent = new Lazy<IPublishedContent>(() => getParent(ParentId));
_getChildren = new Lazy<IEnumerable<IPublishedContent>>(() => getChildren(Id, nav));
_getProperty = getProperty;
_cacheProvider = cacheProvider;
LoadedFromExamine = fromExamine;
ValidateAndSetProperty(valueDictionary, val => _id = Int32.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key");
//ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
ValidateAndSetProperty(valueDictionary, val => _sortOrder = Int32.Parse(val), "sortOrder");
ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName", "__nodeName");
ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName");
ValidateAndSetProperty(valueDictionary, val => _documentTypeAlias = val, "nodeTypeAlias", LuceneIndexer.ItemTypeFieldName);
ValidateAndSetProperty(valueDictionary, val => _documentTypeId = Int32.Parse(val), "nodeType");
//ValidateAndSetProperty(valueDictionary, val => _writerName = val, "writerName");
ValidateAndSetProperty(valueDictionary, val => _creatorName = val, "creatorName", "writerName"); //this is a bit of a hack fix for: U4-1132
//ValidateAndSetProperty(valueDictionary, val => _writerId = int.Parse(val), "writerID");
ValidateAndSetProperty(valueDictionary, val => _creatorId = Int32.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132
ValidateAndSetProperty(valueDictionary, val => _path = val, "path", "__Path");
ValidateAndSetProperty(valueDictionary, val => _createDate = ParseDateTimeValue(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => _updateDate = ParseDateTimeValue(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => _level = Int32.Parse(val), "level");
ValidateAndSetProperty(valueDictionary, val =>
{
int pId;
ParentId = -1;
if (Int32.TryParse(val, out pId))
{
ParentId = pId;
}
}, "parentID");
_contentType = contentTypeCache.Get(PublishedItemType.Media, _documentTypeAlias);
_properties = new Collection<IPublishedProperty>();
//handle content type properties
//make sure we create them even if there's no value
foreach (var propertyType in _contentType.PropertyTypes)
{
var alias = propertyType.Alias;
_keysAdded.Add(alias);
string value;
const bool isPreviewing = false; // false :: never preview a media
var property = valueDictionary.TryGetValue(alias, out value) == false || value == null
? new XmlPublishedProperty(propertyType, this, isPreviewing)
: new XmlPublishedProperty(propertyType, this, isPreviewing, value);
_properties.Add(property);
}
//loop through remaining values that haven't been applied
foreach (var i in valueDictionary.Where(x =>
_keysAdded.Contains(x.Key) == false // not already processed
&& IgnoredKeys.Contains(x.Key) == false)) // not ignorable
{
if (i.Key.InvariantStartsWith("__"))
{
// no type for that one, dunno how to convert, drop it
//IPublishedProperty property = new PropertyResult(i.Key, i.Value, PropertyResultType.CustomProperty);
//_properties.Add(property);
}
else
{
// this is a property that does not correspond to anything, ignore and log
Current.Logger.Warn<PublishedMediaCache>("Dropping property \"" + i.Key + "\" because it does not belong to the content type.");
}
}
}
private DateTime ParseDateTimeValue(string val)
{
if (LoadedFromExamine == false)
return DateTime.Parse(val);
//we need to parse the date time using Lucene converters
var ticks = Int64.Parse(val);
return new DateTime(ticks);
}
/// <summary>
/// Flag to get/set if this was laoded from examine cache
/// </summary>
internal bool LoadedFromExamine { get; }
//private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
private readonly Lazy<IPublishedContent> _getParent;
//private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
private readonly Lazy<IEnumerable<IPublishedContent>> _getChildren;
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
private readonly ICacheProvider _cacheProvider;
/// <summary>
/// Returns 'Media' as the item type
/// </summary>
public override PublishedItemType ItemType => PublishedItemType.Media;
public override IPublishedContent Parent => _getParent.Value;
public int ParentId { get; private set; }
public override int Id => _id;
public override Guid Key => _key;
public override int TemplateId => 0;
public override int SortOrder => _sortOrder;
public override string Name => _name;
public override PublishedCultureInfos GetCulture(string culture = null) => throw new NotSupportedException();
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string UrlSegment => _urlName;
public override string WriterName => _creatorName;
public override string CreatorName => _creatorName;
public override int WriterId => _creatorId;
public override int CreatorId => _creatorId;
public override string Path => _path;
public override DateTime CreateDate => _createDate;
public override DateTime UpdateDate => _updateDate;
public override int Level => _level;
public override bool IsDraft => false;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedContent> Children => _getChildren.Value;
public override IPublishedProperty GetProperty(string alias)
{
return _getProperty(this, alias);
}
public override PublishedContentType ContentType => _contentType;
private readonly List<string> _keysAdded = new List<string>();
private int _id;
private Guid _key;
//private int _templateId;
private int _sortOrder;
private string _name;
private string _urlName;
private string _documentTypeAlias;
private int _documentTypeId;
//private string _writerName;
private string _creatorName;
//private int _writerId;
private int _creatorId;
private string _path;
private DateTime _createDate;
private DateTime _updateDate;
//private Guid _version;
private int _level;
private readonly ICollection<IPublishedProperty> _properties;
private readonly PublishedContentType _contentType;
private void ValidateAndSetProperty(IReadOnlyDictionary<string, string> valueDictionary, Action<string> setProperty, params string[] potentialKeys)
{
var key = potentialKeys.FirstOrDefault(x => valueDictionary.ContainsKey(x) && valueDictionary[x] != null);
if (key == null)
{
throw new FormatException("The valueDictionary is not formatted correctly and is missing any of the '" + String.Join(",", potentialKeys) + "' elements");
}
setProperty(valueDictionary[key]);
_keysAdded.Add(key);
}
}
}

View File

@@ -11,10 +11,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
private readonly IDomainService _domainService;
public DomainCache(IDomainService domainService, ISystemDefaultCultureProvider systemDefaultCultureProvider)
public DomainCache(IDomainService domainService, IDefaultCultureAccessor defaultCultureAccessor)
{
_domainService = domainService;
DefaultCulture = systemDefaultCultureProvider.DefaultCulture;
DefaultCulture = defaultCultureAccessor.DefaultCulture;
}
/// <summary>

View File

@@ -266,7 +266,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
while (hasDomains == false && n != null) // n is null at root
{
// get the url
var urlName = n.UrlName;
var urlName = n.UrlSegment;
pathParts.Add(urlName);
// move to parent node

View File

@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine.Providers;
using Examine.LuceneEngine.SearchCriteria;
using Examine.Providers;
using Lucene.Net.Store;
@@ -16,7 +14,6 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
using Umbraco.Web.Models;
using Umbraco.Examine;
using umbraco;
using Umbraco.Core.Cache;
@@ -607,230 +604,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
return mediaList;
}
/// <summary>
/// An IPublishedContent that is represented all by a dictionary.
/// </summary>
/// <remarks>
/// This is a helper class and definitely not intended for public use, it expects that all of the values required
/// to create an IPublishedContent exist in the dictionary by specific aliases.
/// </remarks>
internal class DictionaryPublishedContent : PublishedContentBase
{
// note: I'm not sure this class fully complies with IPublishedContent rules especially
// I'm not sure that _properties contains all properties including those without a value,
// neither that GetProperty will return a property without a value vs. null... @zpqrtbnk
// List of properties that will appear in the XML and do not match
// anything in the ContentType, so they must be ignored.
private static readonly string[] IgnoredKeys = { "version", "isDoc" };
public DictionaryPublishedContent(
IReadOnlyDictionary<string, string> valueDictionary,
Func<int, IPublishedContent> getParent,
Func<int, XPathNavigator, IEnumerable<IPublishedContent>> getChildren,
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
ICacheProvider cacheProvider,
PublishedContentTypeCache contentTypeCache,
XPathNavigator nav,
bool fromExamine)
{
if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary));
if (getParent == null) throw new ArgumentNullException(nameof(getParent));
if (getProperty == null) throw new ArgumentNullException(nameof(getProperty));
_getParent = new Lazy<IPublishedContent>(() => getParent(ParentId));
_getChildren = new Lazy<IEnumerable<IPublishedContent>>(() => getChildren(Id, nav));
_getProperty = getProperty;
_cacheProvider = cacheProvider;
LoadedFromExamine = fromExamine;
ValidateAndSetProperty(valueDictionary, val => _id = int.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key");
//ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
ValidateAndSetProperty(valueDictionary, val => _sortOrder = int.Parse(val), "sortOrder");
ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName", "__nodeName");
ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName");
ValidateAndSetProperty(valueDictionary, val => _documentTypeAlias = val, "nodeTypeAlias", LuceneIndexer.ItemTypeFieldName);
ValidateAndSetProperty(valueDictionary, val => _documentTypeId = int.Parse(val), "nodeType");
//ValidateAndSetProperty(valueDictionary, val => _writerName = val, "writerName");
ValidateAndSetProperty(valueDictionary, val => _creatorName = val, "creatorName", "writerName"); //this is a bit of a hack fix for: U4-1132
//ValidateAndSetProperty(valueDictionary, val => _writerId = int.Parse(val), "writerID");
ValidateAndSetProperty(valueDictionary, val => _creatorId = int.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132
ValidateAndSetProperty(valueDictionary, val => _path = val, "path", "__Path");
ValidateAndSetProperty(valueDictionary, val => _createDate = ParseDateTimeValue(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => _updateDate = ParseDateTimeValue(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => _level = int.Parse(val), "level");
ValidateAndSetProperty(valueDictionary, val =>
{
int pId;
ParentId = -1;
if (int.TryParse(val, out pId))
{
ParentId = pId;
}
}, "parentID");
_contentType = contentTypeCache.Get(PublishedItemType.Media, _documentTypeAlias);
_properties = new Collection<IPublishedProperty>();
//handle content type properties
//make sure we create them even if there's no value
foreach (var propertyType in _contentType.PropertyTypes)
{
var alias = propertyType.Alias;
_keysAdded.Add(alias);
string value;
const bool isPreviewing = false; // false :: never preview a media
var property = valueDictionary.TryGetValue(alias, out value) == false || value == null
? new XmlPublishedProperty(propertyType, this, isPreviewing)
: new XmlPublishedProperty(propertyType, this, isPreviewing, value);
_properties.Add(property);
}
//loop through remaining values that haven't been applied
foreach (var i in valueDictionary.Where(x =>
_keysAdded.Contains(x.Key) == false // not already processed
&& IgnoredKeys.Contains(x.Key) == false)) // not ignorable
{
if (i.Key.InvariantStartsWith("__"))
{
// no type for that one, dunno how to convert, drop it
//IPublishedProperty property = new PropertyResult(i.Key, i.Value, PropertyResultType.CustomProperty);
//_properties.Add(property);
}
else
{
// this is a property that does not correspond to anything, ignore and log
Current.Logger.Warn<PublishedMediaCache>("Dropping property \"" + i.Key + "\" because it does not belong to the content type.");
}
}
}
private DateTime ParseDateTimeValue(string val)
{
if (LoadedFromExamine == false)
return DateTime.Parse(val);
//we need to parse the date time using Lucene converters
var ticks = long.Parse(val);
return new DateTime(ticks);
}
/// <summary>
/// Flag to get/set if this was laoded from examine cache
/// </summary>
internal bool LoadedFromExamine { get; }
//private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
private readonly Lazy<IPublishedContent> _getParent;
//private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
private readonly Lazy<IEnumerable<IPublishedContent>> _getChildren;
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
private readonly ICacheProvider _cacheProvider;
/// <summary>
/// Returns 'Media' as the item type
/// </summary>
public override PublishedItemType ItemType => PublishedItemType.Media;
public override IPublishedContent Parent => _getParent.Value;
public int ParentId { get; private set; }
public override int Id => _id;
public override Guid Key => _key;
public override int TemplateId => 0;
public override int SortOrder => _sortOrder;
public override string Name => _name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override string UrlName => _urlName;
public override string DocumentTypeAlias => _documentTypeAlias;
public override int DocumentTypeId => _documentTypeId;
public override string WriterName => _creatorName;
public override string CreatorName => _creatorName;
public override int WriterId => _creatorId;
public override int CreatorId => _creatorId;
public override string Path => _path;
public override DateTime CreateDate => _createDate;
public override DateTime UpdateDate => _updateDate;
public override int Level => _level;
public override bool IsDraft => false;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedContent> Children => _getChildren.Value;
public override IPublishedProperty GetProperty(string alias)
{
return _getProperty(this, alias);
}
public override PublishedContentType ContentType => _contentType;
// override to implement cache
// cache at context level, ie once for the whole request
// but cache is not shared by requests because we wouldn't know how to clear it
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
if (recurse == false) return GetProperty(alias);
var key = $"XmlPublishedCache.PublishedMediaCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}";
var cacheProvider = _cacheProvider;
return cacheProvider.GetCacheItem<IPublishedProperty>(key, () => base.GetProperty(alias, true));
}
private readonly List<string> _keysAdded = new List<string>();
private int _id;
private Guid _key;
//private int _templateId;
private int _sortOrder;
private string _name;
private string _urlName;
private string _documentTypeAlias;
private int _documentTypeId;
//private string _writerName;
private string _creatorName;
//private int _writerId;
private int _creatorId;
private string _path;
private DateTime _createDate;
private DateTime _updateDate;
//private Guid _version;
private int _level;
private readonly ICollection<IPublishedProperty> _properties;
private readonly PublishedContentType _contentType;
private void ValidateAndSetProperty(IReadOnlyDictionary<string, string> valueDictionary, Action<string> setProperty, params string[] potentialKeys)
{
var key = potentialKeys.FirstOrDefault(x => valueDictionary.ContainsKey(x) && valueDictionary[x] != null);
if (key == null)
{
throw new FormatException("The valueDictionary is not formatted correctly and is missing any of the '" + string.Join(",", potentialKeys) + "' elements");
}
setProperty(valueDictionary[key]);
_keysAdded.Add(key);
}
}
internal void Resync()
{
// clear recursive properties cached by XmlPublishedContent.GetProperty

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private readonly IUserService _userService;
private readonly ICacheProvider _requestCache;
private readonly IGlobalSettings _globalSettings;
private readonly ISystemDefaultCultureProvider _systemDefaultCultureProvider;
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
private readonly ISiteDomainHelper _siteDomainHelper;
#region Constructors
@@ -43,17 +43,18 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IScopeProvider scopeProvider,
ICacheProvider requestCache,
IEnumerable<IUrlSegmentProvider> segmentProviders,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
ISystemDefaultCultureProvider systemDefaultCultureProvider,
IDefaultCultureAccessor defaultCultureAccessor,
ILogger logger,
IGlobalSettings globalSettings,
ISiteDomainHelper siteDomainHelper,
MainDom mainDom,
bool testing = false, bool enableRepositoryEvents = true)
: this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, segmentProviders, publishedSnapshotAccessor,
: this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, segmentProviders,
publishedSnapshotAccessor, variationContextAccessor,
documentRepository, mediaRepository, memberRepository,
systemDefaultCultureProvider,
defaultCultureAccessor,
logger, globalSettings, siteDomainHelper, null, mainDom, testing, enableRepositoryEvents)
{ }
@@ -62,18 +63,19 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IPublishedContentTypeFactory publishedContentTypeFactory,
IScopeProvider scopeProvider,
ICacheProvider requestCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
ISystemDefaultCultureProvider systemDefaultCultureProvider,
IDefaultCultureAccessor defaultCultureAccessor,
ILogger logger,
IGlobalSettings globalSettings,
ISiteDomainHelper siteDomainHelper,
PublishedContentTypeCache contentTypeCache,
MainDom mainDom,
bool testing, bool enableRepositoryEvents)
: this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, Enumerable.Empty<IUrlSegmentProvider>(), publishedSnapshotAccessor,
: this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, Enumerable.Empty<IUrlSegmentProvider>(),
publishedSnapshotAccessor, variationContextAccessor,
documentRepository, mediaRepository, memberRepository,
systemDefaultCultureProvider,
defaultCultureAccessor,
logger, globalSettings, siteDomainHelper, contentTypeCache, mainDom, testing, enableRepositoryEvents)
{ }
@@ -82,16 +84,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IScopeProvider scopeProvider,
ICacheProvider requestCache,
IEnumerable<IUrlSegmentProvider> segmentProviders,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
ISystemDefaultCultureProvider systemDefaultCultureProvider,
IDefaultCultureAccessor defaultCultureAccessor,
ILogger logger,
IGlobalSettings globalSettings,
ISiteDomainHelper siteDomainHelper,
PublishedContentTypeCache contentTypeCache,
MainDom mainDom,
bool testing, bool enableRepositoryEvents)
: base(publishedSnapshotAccessor)
: base(publishedSnapshotAccessor, variationContextAccessor)
{
_routesCache = new RoutesCache();
_publishedContentTypeFactory = publishedContentTypeFactory;
@@ -106,7 +108,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
_memberService = serviceContext.MemberService;
_mediaService = serviceContext.MediaService;
_userService = serviceContext.UserService;
_systemDefaultCultureProvider = systemDefaultCultureProvider;
_defaultCultureAccessor = defaultCultureAccessor;
_requestCache = requestCache;
_globalSettings = globalSettings;
@@ -151,7 +153,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
// the current caches, but that would mean creating an extra cache (StaticCache
// probably) so better use RequestCache.
var domainCache = new DomainCache(_domainService, _systemDefaultCultureProvider);
var domainCache = new DomainCache(_domainService, _defaultCultureAccessor);
return new PublishedSnapshot(
new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper, _contentTypeCache, _routesCache, previewToken),

View File

@@ -29,10 +29,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
factory.GetInstance<CacheHelper>().RequestCache,
factory.GetInstance<UrlSegmentProviderCollection>(),
factory.GetInstance<IPublishedSnapshotAccessor>(),
factory.GetInstance<IVariationContextAccessor>(),
factory.GetInstance<IDocumentRepository>(),
factory.GetInstance<IMediaRepository>(),
factory.GetInstance<IMemberRepository>(),
factory.GetInstance<ISystemDefaultCultureProvider>(),
factory.GetInstance<IDefaultCultureAccessor>(),
factory.GetInstance<ILogger>(),
factory.GetInstance<IGlobalSettings>(),
factory.GetInstance<ISiteDomainHelper>(),

View File

@@ -79,20 +79,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
return _properties.TryGetValue(alias, out property) ? property : null;
}
// override to implement cache
// cache at context level, ie once for the whole request
// but cache is not shared by requests because we wouldn't know how to clear it
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
if (recurse == false) return GetProperty(alias);
var key = $"XmlPublishedCache.PublishedContentCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}";
var cacheProvider = _cacheProvider;
return cacheProvider.GetCacheItem<IPublishedProperty>(key, () => base.GetProperty(alias, true));
// note: cleared by PublishedContentCache.Resync - any change here must be applied there
}
public override PublishedItemType ItemType => PublishedItemType.Content;
public override IPublishedContent Parent
@@ -150,25 +136,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
}
}
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override PublishedCultureInfos GetCulture(string culture = null) => throw new NotSupportedException();
public override string DocumentTypeAlias
{
get
{
if (_nodeInitialized == false) InitializeNode();
return _docTypeAlias;
}
}
public override int DocumentTypeId
{
get
{
if (_nodeInitialized == false) InitializeNode();
return _docTypeId;
}
}
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string WriterName
{
@@ -233,7 +203,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
}
}
public override string UrlName
public override string UrlSegment
{
get
{