diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index 90442c5e7f..9222769247 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Linq.Expressions;
using System.Net.Http.Headers;
using System.Text;
+using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dynamics;
@@ -688,6 +689,77 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
+
+ ///
+ /// This builds the Xml document used for the XML cache
+ ///
+ ///
+ public XmlDocument BuildXmlCache()
+ {
+ //TODO: This is what we should do , but converting to use XDocument would be breaking unless we convert
+ // to XmlDocument at the end of this, but again, this would be bad for memory... though still not nearly as
+ // bad as what is happening before!
+ // We'll keep using XmlDocument for now though, but XDocument xml generation is much faster:
+ // https://blogs.msdn.microsoft.com/codejunkie/2008/10/08/xmldocument-vs-xelement-performance/
+ // I think we already have code in here to convert XDocument to XmlDocument but in case we don't here
+ // it is: https://blogs.msdn.microsoft.com/marcelolr/2009/03/13/fast-way-to-convert-xmldocument-into-xdocument/
+
+ //// Prepare an XmlDocument with an appropriate inline DTD to match
+ //// the expected content
+ //var parent = new XElement("root", new XAttribute("id", "-1"));
+ //var xmlDoc = new XDocument(
+ // new XDocumentType("root", null, null, DocumentType.GenerateDtd()),
+ // parent);
+
+ var xmlDoc = new XmlDocument();
+ var doctype = xmlDoc.CreateDocumentType("root", null, null,
+ ApplicationContext.Current.Services.ContentTypeService.GetContentTypesDtd());
+ xmlDoc.AppendChild(doctype);
+ var parent = xmlDoc.CreateElement("root");
+ var pIdAtt = xmlDoc.CreateAttribute("id");
+ pIdAtt.Value = "-1";
+ parent.Attributes.Append(pIdAtt);
+ xmlDoc.AppendChild(parent);
+
+ const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode
+inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
+where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1)
+order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
+
+ XmlElement last = null;
+
+ //NOTE: Query creates a reader - does not load all into memory
+ foreach (var row in Database.Query(sql, new { type = new Guid(Constants.ObjectTypes.Document) }))
+ {
+ string parentId = ((int)row.parentID).ToInvariantString();
+ string xml = row.xml;
+ int sortOrder = row.sortOrder;
+
+ //if the parentid is changing
+ if (last != null && last.GetAttribute("parentID") != parentId)
+ {
+ parent = xmlDoc.GetElementById(parentId);
+ if (parent == null)
+ {
+ //Need to short circuit here, if the parent is not there it means that the parent is unpublished
+ // and therefore the child is not published either so cannot be included in the xml cache
+ continue;
+ }
+ }
+
+ var xmlDocFragment = xmlDoc.CreateDocumentFragment();
+ xmlDocFragment.InnerXml = xml;
+
+ last = (XmlElement)parent.AppendChild(xmlDocFragment);
+
+ // fix sortOrder - see notes in UpdateSortOrder
+ last.Attributes["sortOrder"].Value = sortOrder.ToInvariantString();
+ }
+
+ return xmlDoc;
+
+ }
+
public int CountPublished()
{
var sql = GetBaseQuery(true).Where(x => x.Trashed == false)
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
index c18765239b..e2555995d2 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
+using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -11,6 +12,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentRepository : IRepositoryVersionable, IRecycleBinRepository, IDeleteMediaFilesRepository
{
+ ///
+ /// This builds the Xml document used for the XML cache
+ ///
+ ///
+ XmlDocument BuildXmlCache();
+
///
/// Get the count of published items
///
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 7fcb915b30..cbcd5ecc05 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Threading;
+using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
@@ -636,7 +637,7 @@ namespace Umbraco.Core.Services
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
}
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
-
+
return contents;
}
}
@@ -1714,6 +1715,20 @@ namespace Umbraco.Core.Services
return true;
}
+ ///
+ /// This builds the Xml document used for the XML cache
+ ///
+ ///
+ public XmlDocument BuildXmlCache()
+ {
+ var uow = UowProvider.GetUnitOfWork();
+ using (var repository = RepositoryFactory.CreateContentRepository(uow))
+ {
+ var result = repository.BuildXmlCache();
+ return result;
+ }
+ }
+
///
/// Rebuilds all xml content in the cmsContentXml table for all documents
///
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index 5e90559233..fa4130f8c4 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Xml;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -94,6 +95,12 @@ namespace Umbraco.Core.Services
///
public interface IContentService : IService
{
+ ///
+ /// This builds the Xml document used for the XML cache
+ ///
+ ///
+ XmlDocument BuildXmlCache();
+
///
/// Rebuilds all xml content in the cmsContentXml table for all documents
///
diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs
index 6c4eef7862..777fe80782 100644
--- a/src/Umbraco.Web/umbraco.presentation/content.cs
+++ b/src/Umbraco.Web/umbraco.presentation/content.cs
@@ -482,7 +482,7 @@ namespace umbraco
if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null && UmbracoContext.Current.HttpContext.Items.Contains(XmlContextContentItemKey))
UmbracoContext.Current.HttpContext.Items.Remove(XmlContextContentItemKey);
}
-
+
///
/// Load content from database
///
@@ -490,81 +490,13 @@ namespace umbraco
{
try
{
- // Try to log to the DB
LogHelper.Info("Loading content from database...");
-
- try
+
+ lock (DbReadSyncLock)
{
- LogHelper.Debug("Republishing starting");
-
- lock (DbReadSyncLock)
- {
- //TODO: This is what we should do , but converting to use XDocument would be breaking unless we convert
- // to XmlDocument at the end of this, but again, this would be bad for memory... though still not nearly as
- // bad as what is happening before!
- // We'll keep using XmlDocument for now though, but XDocument xml generation is much faster:
- // https://blogs.msdn.microsoft.com/codejunkie/2008/10/08/xmldocument-vs-xelement-performance/
- // I think we already have code in here to convert XDocument to XmlDocument but in case we don't here
- // it is: https://blogs.msdn.microsoft.com/marcelolr/2009/03/13/fast-way-to-convert-xmldocument-into-xdocument/
-
- //// Prepare an XmlDocument with an appropriate inline DTD to match
- //// the expected content
- //var parent = new XElement("root", new XAttribute("id", "-1"));
- //var xmlDoc = new XDocument(
- // new XDocumentType("root", null, null, DocumentType.GenerateDtd()),
- // parent);
-
- var xmlDoc = new XmlDocument();
- var doctype = xmlDoc.CreateDocumentType("root", null, null,
- ApplicationContext.Current.Services.ContentTypeService.GetContentTypesDtd());
- xmlDoc.AppendChild(doctype);
- var parent = xmlDoc.CreateElement("root");
- var pIdAtt = xmlDoc.CreateAttribute("id");
- pIdAtt.Value = "-1";
- parent.Attributes.Append(pIdAtt);
- xmlDoc.AppendChild(parent);
-
- // Esben Carlsen: At some point we really need to put all data access into to a tier of its own.
- // CLN - added checks that document xml is for a document that is actually published.
- const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode
-inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
-where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1)
-order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
-
- XmlElement last = null;
-
- var db = ApplicationContext.Current.DatabaseContext.Database;
- //NOTE: Query creates a reader - does not load all into memory
- foreach (var row in db.Query(sql, new { type = new Guid(Constants.ObjectTypes.Document)}))
- {
- string parentId = ((int)row.parentID).ToInvariantString();
- string xml = row.xml;
- int sortOrder = row.sortOrder;
-
- //if the parentid is changing
- if (last != null && last.GetAttribute("parentID") != parentId)
- {
- parent = xmlDoc.GetElementById(parentId);
- if (parent == null) throw new InvalidOperationException("No parent node found in xml doc with id " + parentId);
- }
-
- var xmlDocFragment = xmlDoc.CreateDocumentFragment();
- xmlDocFragment.InnerXml = xml;
-
- last = (XmlElement)parent.AppendChild(xmlDocFragment);
-
- // fix sortOrder - see notes in UpdateSortOrder
- last.Attributes["sortOrder"].Value = sortOrder.ToInvariantString();
- }
-
- LogHelper.Debug("Done republishing Xml Index");
-
- return xmlDoc;
- }
- }
- catch (Exception ee)
- {
- LogHelper.Error("Error Republishing", ee);
+ var xmlDoc = ApplicationContext.Current.Services.ContentService.BuildXmlCache();
+ LogHelper.Debug("Done republishing Xml Index");
+ return xmlDoc;
}
}
catch (Exception ee)