diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs index 1875ae03b3..d586bc155a 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs @@ -106,12 +106,13 @@ namespace Umbraco.Core.Models.PublishedContent /// The property type alias. /// The datatype definition identifier. /// The property editor alias. + /// Generally used only for testing, in production this will always be true /// /// The new published property type does not belong to a published content type. /// The values of and are /// assumed to be valid and consistent. /// - internal PublishedPropertyType(string propertyTypeAlias, int dataTypeDefinitionId, string propertyEditorAlias) + internal PublishedPropertyType(string propertyTypeAlias, int dataTypeDefinitionId, string propertyEditorAlias, bool initConverters = true) { // ContentType // - in unit tests, to be set by PublishedContentType when creating it @@ -122,7 +123,8 @@ namespace Umbraco.Core.Models.PublishedContent DataTypeId = dataTypeDefinitionId; PropertyEditorAlias = propertyEditorAlias; - InitializeConverters(); + if (initConverters) + InitializeConverters(); } #endregion diff --git a/src/Umbraco.Tests.Benchmarks/Program.cs b/src/Umbraco.Tests.Benchmarks/Program.cs index eb49f153cc..c8487f677c 100644 --- a/src/Umbraco.Tests.Benchmarks/Program.cs +++ b/src/Umbraco.Tests.Benchmarks/Program.cs @@ -13,7 +13,10 @@ namespace Umbraco.Tests.Benchmarks typeof(BulkInsertBenchmarks), typeof(ModelToSqlExpressionHelperBenchmarks), typeof(XmlBenchmarks), - typeof(LinqCastBenchmarks) + typeof(LinqCastBenchmarks), + typeof(DeepCloneBenchmarks), + typeof(XmlPublishedContentInitBenchmarks), + }); switcher.Run(args); } diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 39d77bbc26..d1fdcaa68f 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -85,12 +85,14 @@ + + @@ -105,6 +107,10 @@ {5d3b8245-ada6-453f-a008-50ed04bfe770} Umbraco.Tests + + {651e1350-91b6-44b7-bd60-7207006d7003} + Umbraco.Web + diff --git a/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs new file mode 100644 index 0000000000..e26022d8e7 --- /dev/null +++ b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnostics.Windows; +using BenchmarkDotNet.Jobs; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.PublishedCache.XmlPublishedCache; + +namespace Umbraco.Tests.Benchmarks +{ + [Config(typeof(Config))] + public class XmlPublishedContentInitBenchmarks + { + private class Config : ManualConfig + { + public Config() + { + Add(new MemoryDiagnoser()); + + //The 'quick and dirty' settings, so it runs a little quicker + // see benchmarkdotnet FAQ + Add(Job.Default + .WithLaunchCount(1) // benchmark process will be launched only once + .WithIterationTime(100) // 100ms per iteration + .WithWarmupCount(3) // 3 warmup iteration + .WithTargetCount(3)); // 3 target iteration + } + } + + public XmlPublishedContentInitBenchmarks() + { + _xml10 = Build(10); + _xml100 = Build(100); + _xml1000 = Build(1000); + _xml10000 = Build(10000); + } + + private readonly string[] _intAttributes = { "id", "parentID", "nodeType", "level", "writerID", "creatorID", "template", "sortOrder", "isDoc", "isDraft" }; + private readonly string[] _strAttributes = { "nodeName", "urlName", "writerName", "creatorName", "path" }; + private readonly string[] _dateAttributes = { "createDate", "updateDate" }; + private readonly string[] _guidAttributes = { "key", "version" }; + + private XmlDocument Build(int children) + { + var xml = new XmlDocument(); + var root = Build(xml, "Home", 10); + for (int i = 0; i < children; i++) + { + var child = Build(xml, "child" + i, 10); + root.AppendChild(child); + } + xml.AppendChild(root); + return xml; + } + + private XmlElement Build(XmlDocument xml, string name, int propertyCount) + { + var random = new Random(); + var content = xml.CreateElement(name); + foreach (var p in _intAttributes) + { + var a = xml.CreateAttribute(p); + a.Value = random.Next(1, 9).ToInvariantString(); + content.Attributes.Append(a); + } + foreach (var p in _strAttributes) + { + var a = xml.CreateAttribute(p); + a.Value = Guid.NewGuid().ToString(); + content.Attributes.Append(a); + } + foreach (var p in _guidAttributes) + { + var a = xml.CreateAttribute(p); + a.Value = Guid.NewGuid().ToString(); + content.Attributes.Append(a); + } + foreach (var p in _dateAttributes) + { + var a = xml.CreateAttribute(p); + a.Value = DateTime.Now.ToString("o"); + content.Attributes.Append(a); + } + + for (int i = 0; i < propertyCount; i++) + { + var prop = xml.CreateElement("prop" + i); + var cdata = xml.CreateCDataSection(string.Join("", Enumerable.Range(0, 10).Select(x => Guid.NewGuid().ToString()))); + prop.AppendChild(cdata); + content.AppendChild(prop); + } + + return content; + } + + private readonly XmlDocument _xml10; + private readonly XmlDocument _xml100; + private readonly XmlDocument _xml1000; + private readonly XmlDocument _xml10000; + + //out props + int id, nodeType, level, writerId, creatorId, template, sortOrder; + Guid key, version; + string name, urlName, writerName, creatorName, docTypeAlias, path; + bool isDraft; + DateTime createDate, updateDate; + PublishedContentType publishedContentType; + Dictionary properties; + + [Benchmark(Baseline = true, OperationsPerInvoke = 10)] + public void Original_10_Children() + { + OriginalInitializeNode(_xml10.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Original_100_Children() + { + OriginalInitializeNode(_xml100.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Original_1000_Children() + { + OriginalInitializeNode(_xml1000.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Original_10000_Children() + { + OriginalInitializeNode(_xml10000.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Enhanced_10_Children() + { + XmlPublishedContent.InitializeNode(_xml10.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties, GetPublishedContentType); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Enhanced_100_Children() + { + XmlPublishedContent.InitializeNode(_xml100.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties, GetPublishedContentType); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Enhanced_1000_Children() + { + XmlPublishedContent.InitializeNode(_xml1000.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties, GetPublishedContentType); + } + + [Benchmark(OperationsPerInvoke = 10)] + public void Enhanced_10000_Children() + { + XmlPublishedContent.InitializeNode(_xml10000.DocumentElement, false, false, + out id, out key, out template, out sortOrder, out name, out writerName, out urlName, + out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, + out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out properties, GetPublishedContentType); + } + + + internal static void OriginalInitializeNode(XmlNode xmlNode, bool legacy, bool isPreviewing, + out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName, + out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, + out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, + out PublishedContentType contentType, out Dictionary properties) + { + //initialize the out params with defaults: + writerName = null; + docTypeAlias = null; + id = template = sortOrder = template = creatorId = writerId = docTypeId = level = default(int); + key = version = default(Guid); + name = writerName = urlName = creatorName = docTypeAlias = path = null; + createDate = updateDate = default(DateTime); + isDraft = false; + contentType = null; + properties = null; + + //return if this is null + if (xmlNode == null) + { + return; + } + + if (xmlNode.Attributes != null) + { + id = int.Parse(xmlNode.Attributes.GetNamedItem("id").Value); + if (xmlNode.Attributes.GetNamedItem("key") != null) // because, migration + key = Guid.Parse(xmlNode.Attributes.GetNamedItem("key").Value); + if (xmlNode.Attributes.GetNamedItem("template") != null) + template = int.Parse(xmlNode.Attributes.GetNamedItem("template").Value); + if (xmlNode.Attributes.GetNamedItem("sortOrder") != null) + sortOrder = int.Parse(xmlNode.Attributes.GetNamedItem("sortOrder").Value); + if (xmlNode.Attributes.GetNamedItem("nodeName") != null) + name = xmlNode.Attributes.GetNamedItem("nodeName").Value; + if (xmlNode.Attributes.GetNamedItem("writerName") != null) + writerName = xmlNode.Attributes.GetNamedItem("writerName").Value; + if (xmlNode.Attributes.GetNamedItem("urlName") != null) + urlName = xmlNode.Attributes.GetNamedItem("urlName").Value; + // Creatorname is new in 2.1, so published xml might not have it! + try + { + creatorName = xmlNode.Attributes.GetNamedItem("creatorName").Value; + } + catch + { + creatorName = writerName; + } + + //Added the actual userID, as a user cannot be looked up via full name only... + if (xmlNode.Attributes.GetNamedItem("creatorID") != null) + creatorId = int.Parse(xmlNode.Attributes.GetNamedItem("creatorID").Value); + if (xmlNode.Attributes.GetNamedItem("writerID") != null) + writerId = int.Parse(xmlNode.Attributes.GetNamedItem("writerID").Value); + + if (legacy) + { + if (xmlNode.Attributes.GetNamedItem("nodeTypeAlias") != null) + docTypeAlias = xmlNode.Attributes.GetNamedItem("nodeTypeAlias").Value; + } + else + { + docTypeAlias = xmlNode.Name; + } + + if (xmlNode.Attributes.GetNamedItem("nodeType") != null) + docTypeId = int.Parse(xmlNode.Attributes.GetNamedItem("nodeType").Value); + if (xmlNode.Attributes.GetNamedItem("path") != null) + path = xmlNode.Attributes.GetNamedItem("path").Value; + if (xmlNode.Attributes.GetNamedItem("version") != null) + version = new Guid(xmlNode.Attributes.GetNamedItem("version").Value); + if (xmlNode.Attributes.GetNamedItem("createDate") != null) + createDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("createDate").Value); + if (xmlNode.Attributes.GetNamedItem("updateDate") != null) + updateDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("updateDate").Value); + if (xmlNode.Attributes.GetNamedItem("level") != null) + level = int.Parse(xmlNode.Attributes.GetNamedItem("level").Value); + + isDraft = (xmlNode.Attributes.GetNamedItem("isDraft") != null); + } + + // load data + + var dataXPath = legacy ? "data" : "* [not(@isDoc)]"; + var nodes = xmlNode.SelectNodes(dataXPath); + + contentType = GetPublishedContentType(PublishedItemType.Content, docTypeAlias); + + var propertyNodes = new Dictionary(); + if (nodes != null) + foreach (XmlNode n in nodes) + { + var attrs = n.Attributes; + if (attrs == null) continue; + var alias = legacy + ? attrs.GetNamedItem("alias").Value + : n.Name; + propertyNodes[alias.ToLowerInvariant()] = n; + } + properties = contentType.PropertyTypes.Select(p => + { + XmlNode n; + return propertyNodes.TryGetValue(p.PropertyTypeAlias.ToLowerInvariant(), out n) + ? new XmlPublishedProperty(p, isPreviewing, n) + : new XmlPublishedProperty(p, isPreviewing); + }).Cast().ToDictionary( + x => x.PropertyTypeAlias, + x => x, + StringComparer.OrdinalIgnoreCase); + } + + private static PublishedContentType GetPublishedContentType(PublishedItemType type, string alias) + { + return new PublishedContentType(alias, new string[] {}, + new List(Enumerable.Range(0, 10).Select(x => new PublishedPropertyType("prop" + x, 0, "test", initConverters:false)))); + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Properties/AssemblyInfo.cs b/src/Umbraco.Web/Properties/AssemblyInfo.cs index 89499b833e..3509b2e650 100644 --- a/src/Umbraco.Web/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Web/Properties/AssemblyInfo.cs @@ -28,6 +28,7 @@ using System.Security; [assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)] [assembly: InternalsVisibleTo("Umbraco.Tests")] +[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")] [assembly: InternalsVisibleTo("umbraco.MacroEngines")] [assembly: InternalsVisibleTo("Umbraco.Web.UI")] [assembly: InternalsVisibleTo("umbraco.webservices")] diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index 5de94f6749..202fe551c7 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -313,72 +313,103 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _parentInitialized = true; } - private void InitializeNode() - { - if (_xmlNode == null) return; + private void InitializeNode() + { + InitializeNode(_xmlNode, UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema, _isPreviewing, + out _id, out _key, out _template, out _sortOrder, out _name, out _writerName, + out _urlName, out _creatorName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path, + out _version, out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties, + PublishedContentType.Get); - if (_xmlNode.Attributes != null) + // warn: this is not thread-safe... + _nodeInitialized = true; + } + + internal static void InitializeNode(XmlNode xmlNode, bool legacy, bool isPreviewing, + out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName, + out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, + out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, + out PublishedContentType contentType, out Dictionary properties, + Func getPublishedContentType) + { + //initialize the out params with defaults: + writerName = null; + docTypeAlias = null; + id = template = sortOrder = template = creatorId = writerId = docTypeId = level = default(int); + key = version = default(Guid); + name = writerName = urlName = creatorName = docTypeAlias = path = null; + createDate = updateDate = default(DateTime); + isDraft = false; + contentType = null; + properties = null; + + //return if this is null + if (xmlNode == null) + { + return; + } + + if (xmlNode.Attributes != null) { - _id = int.Parse(_xmlNode.Attributes.GetNamedItem("id").Value); - if (_xmlNode.Attributes.GetNamedItem("key") != null) // because, migration - _key = Guid.Parse(_xmlNode.Attributes.GetNamedItem("key").Value); - if (_xmlNode.Attributes.GetNamedItem("template") != null) - _template = int.Parse(_xmlNode.Attributes.GetNamedItem("template").Value); - if (_xmlNode.Attributes.GetNamedItem("sortOrder") != null) - _sortOrder = int.Parse(_xmlNode.Attributes.GetNamedItem("sortOrder").Value); - if (_xmlNode.Attributes.GetNamedItem("nodeName") != null) - _name = _xmlNode.Attributes.GetNamedItem("nodeName").Value; - if (_xmlNode.Attributes.GetNamedItem("writerName") != null) - _writerName = _xmlNode.Attributes.GetNamedItem("writerName").Value; - if (_xmlNode.Attributes.GetNamedItem("urlName") != null) - _urlName = _xmlNode.Attributes.GetNamedItem("urlName").Value; + id = int.Parse(xmlNode.Attributes.GetNamedItem("id").Value); + if (xmlNode.Attributes.GetNamedItem("key") != null) // because, migration + key = Guid.Parse(xmlNode.Attributes.GetNamedItem("key").Value); + if (xmlNode.Attributes.GetNamedItem("template") != null) + template = int.Parse(xmlNode.Attributes.GetNamedItem("template").Value); + if (xmlNode.Attributes.GetNamedItem("sortOrder") != null) + sortOrder = int.Parse(xmlNode.Attributes.GetNamedItem("sortOrder").Value); + if (xmlNode.Attributes.GetNamedItem("nodeName") != null) + name = xmlNode.Attributes.GetNamedItem("nodeName").Value; + if (xmlNode.Attributes.GetNamedItem("writerName") != null) + writerName = xmlNode.Attributes.GetNamedItem("writerName").Value; + if (xmlNode.Attributes.GetNamedItem("urlName") != null) + urlName = xmlNode.Attributes.GetNamedItem("urlName").Value; // Creatorname is new in 2.1, so published xml might not have it! try { - _creatorName = _xmlNode.Attributes.GetNamedItem("creatorName").Value; + creatorName = xmlNode.Attributes.GetNamedItem("creatorName").Value; } catch { - _creatorName = _writerName; + creatorName = writerName; } //Added the actual userID, as a user cannot be looked up via full name only... - if (_xmlNode.Attributes.GetNamedItem("creatorID") != null) - _creatorId = int.Parse(_xmlNode.Attributes.GetNamedItem("creatorID").Value); - if (_xmlNode.Attributes.GetNamedItem("writerID") != null) - _writerId = int.Parse(_xmlNode.Attributes.GetNamedItem("writerID").Value); + if (xmlNode.Attributes.GetNamedItem("creatorID") != null) + creatorId = int.Parse(xmlNode.Attributes.GetNamedItem("creatorID").Value); + if (xmlNode.Attributes.GetNamedItem("writerID") != null) + writerId = int.Parse(xmlNode.Attributes.GetNamedItem("writerID").Value); - if (UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema) + if (legacy) { - if (_xmlNode.Attributes.GetNamedItem("nodeTypeAlias") != null) - _docTypeAlias = _xmlNode.Attributes.GetNamedItem("nodeTypeAlias").Value; + if (xmlNode.Attributes.GetNamedItem("nodeTypeAlias") != null) + docTypeAlias = xmlNode.Attributes.GetNamedItem("nodeTypeAlias").Value; } else { - _docTypeAlias = _xmlNode.Name; + docTypeAlias = xmlNode.Name; } - if (_xmlNode.Attributes.GetNamedItem("nodeType") != null) - _docTypeId = int.Parse(_xmlNode.Attributes.GetNamedItem("nodeType").Value); - if (_xmlNode.Attributes.GetNamedItem("path") != null) - _path = _xmlNode.Attributes.GetNamedItem("path").Value; - if (_xmlNode.Attributes.GetNamedItem("version") != null) - _version = new Guid(_xmlNode.Attributes.GetNamedItem("version").Value); - if (_xmlNode.Attributes.GetNamedItem("createDate") != null) - _createDate = DateTime.Parse(_xmlNode.Attributes.GetNamedItem("createDate").Value); - if (_xmlNode.Attributes.GetNamedItem("updateDate") != null) - _updateDate = DateTime.Parse(_xmlNode.Attributes.GetNamedItem("updateDate").Value); - if (_xmlNode.Attributes.GetNamedItem("level") != null) - _level = int.Parse(_xmlNode.Attributes.GetNamedItem("level").Value); + if (xmlNode.Attributes.GetNamedItem("nodeType") != null) + docTypeId = int.Parse(xmlNode.Attributes.GetNamedItem("nodeType").Value); + if (xmlNode.Attributes.GetNamedItem("path") != null) + path = xmlNode.Attributes.GetNamedItem("path").Value; + if (xmlNode.Attributes.GetNamedItem("version") != null) + version = new Guid(xmlNode.Attributes.GetNamedItem("version").Value); + if (xmlNode.Attributes.GetNamedItem("createDate") != null) + createDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("createDate").Value); + if (xmlNode.Attributes.GetNamedItem("updateDate") != null) + updateDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("updateDate").Value); + if (xmlNode.Attributes.GetNamedItem("level") != null) + level = int.Parse(xmlNode.Attributes.GetNamedItem("level").Value); - _isDraft = (_xmlNode.Attributes.GetNamedItem("isDraft") != null); + isDraft = (xmlNode.Attributes.GetNamedItem("isDraft") != null); } //dictionary to store the property node data var propertyNodes = new Dictionary(); - - var legacy = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema; - foreach (XmlNode n in _xmlNode.ChildNodes) + + foreach (XmlNode n in xmlNode.ChildNodes) { var e = n as XmlElement; if (e == null) continue; @@ -386,7 +417,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { if (n.Name == "data") { - PopulatePropertyNodes(propertyNodes, e); + PopulatePropertyNodes(propertyNodes, e, true); } else break; //we are not longer on property elements } @@ -394,37 +425,34 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { if (e.HasAttribute("isDoc") == false) { - PopulatePropertyNodes(propertyNodes, e); + PopulatePropertyNodes(propertyNodes, e, false); } else break; //we are not longer on property elements } } //lookup the content type and create the properties collection - _contentType = PublishedContentType.Get(PublishedItemType.Content, _docTypeAlias); - _properties = new Dictionary(StringComparer.OrdinalIgnoreCase); + contentType = getPublishedContentType(PublishedItemType.Content, docTypeAlias); + properties = new Dictionary(StringComparer.OrdinalIgnoreCase); //fill in the property collection - foreach (var propertyType in _contentType.PropertyTypes) + foreach (var propertyType in contentType.PropertyTypes) { XmlNode n; var val = propertyNodes.TryGetValue(propertyType.PropertyTypeAlias.ToLowerInvariant(), out n) - ? new XmlPublishedProperty(propertyType, _isPreviewing, n) - : new XmlPublishedProperty(propertyType, _isPreviewing); + ? new XmlPublishedProperty(propertyType, isPreviewing, n) + : new XmlPublishedProperty(propertyType, isPreviewing); - _properties[propertyType.PropertyTypeAlias] = val; + properties[propertyType.PropertyTypeAlias] = val; } - - // warn: this is not thread-safe... - _nodeInitialized = true; } - private void PopulatePropertyNodes(IDictionary propertyNodes, XmlNode n) + private static void PopulatePropertyNodes(IDictionary propertyNodes, XmlNode n, bool legacy) { var attrs = n.Attributes; if (attrs == null) return; - var alias = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema + var alias = legacy ? attrs.GetNamedItem("alias").Value : n.Name; propertyNodes[alias.ToLowerInvariant()] = n;