diff --git a/src/Umbraco.Web/Macros/PartialViewMacroController.cs b/src/Umbraco.Web/Macros/PartialViewMacroController.cs index e275464b20..df6a939632 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroController.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Web.Mvc; +using Umbraco.Core.Models; using Umbraco.Web.Models; using Umbraco.Web.Mvc; using umbraco.cms.businesslogic.macro; @@ -14,15 +15,13 @@ namespace Umbraco.Web.Macros [MergeParentContextViewData] internal class PartialViewMacroController : Controller { - private readonly UmbracoContext _umbracoContext; private readonly MacroModel _macro; - private readonly INode _currentPage; + private readonly IPublishedContent _content; - public PartialViewMacroController(UmbracoContext umbracoContext, MacroModel macro, INode currentPage) + public PartialViewMacroController(MacroModel macro, IPublishedContent content) { - _umbracoContext = umbracoContext; _macro = macro; - _currentPage = currentPage; + _content = content; } /// @@ -33,13 +32,12 @@ namespace Umbraco.Web.Macros public PartialViewResult Index() { var model = new PartialViewMacroModel( - _umbracoContext.ContentCache.GetById(_currentPage.Id), //_currentPage.ConvertFromNode(), + _content, _macro.Id, _macro.Alias, _macro.Name, _macro.Properties.ToDictionary(x => x.Key, x => (object)x.Value)); return PartialView(_macro.ScriptName, model); } - } } \ No newline at end of file diff --git a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs index 507b9fbb6e..aa88de9348 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs @@ -10,6 +10,7 @@ using System.Web.Routing; using System.Web.WebPages; using Umbraco.Core.IO; using umbraco.cms.businesslogic.macro; +using Umbraco.Core.Models; using umbraco.interfaces; using Umbraco.Web.Mvc; using Umbraco.Core; @@ -98,10 +99,16 @@ namespace Umbraco.Web.Macros return true; } - public string Execute(MacroModel macro, INode currentPage) + public string Execute(MacroModel macro, INode node) + { + var umbCtx = _getUmbracoContext(); + return Execute(macro, umbCtx.ContentCache.GetById(node.Id)); + } + + public string Execute(MacroModel macro, IPublishedContent content) { if (macro == null) throw new ArgumentNullException("macro"); - if (currentPage == null) throw new ArgumentNullException("currentPage"); + if (content == null) throw new ArgumentNullException("content"); if (macro.ScriptName.IsNullOrWhiteSpace()) throw new ArgumentException("The ScriptName property of the macro object cannot be null or empty"); var http = _getHttpContext(); @@ -127,7 +134,7 @@ namespace Umbraco.Web.Macros var request = new RequestContext(http, routeVals); string output; - using (var controller = new PartialViewMacroController(umbCtx, macro, currentPage)) + using (var controller = new PartialViewMacroController(macro, content)) { //bubble up the model state from the main view context to our custom controller. //when merging we'll create a new dictionary, otherwise you might run into an enumeration error diff --git a/src/Umbraco.Web/Media/ImageUrl.cs b/src/Umbraco.Web/Media/ImageUrl.cs index f3c151f7aa..8f56d8bfa4 100644 --- a/src/Umbraco.Web/Media/ImageUrl.cs +++ b/src/Umbraco.Web/Media/ImageUrl.cs @@ -47,9 +47,9 @@ namespace Umbraco.Web.Media } else { - var itemPage = new page(content.Instance.XmlContent.GetElementById(nodeId.GetValueOrDefault().ToString(CultureInfo.InvariantCulture))); - var value = itemPage.Elements[field]; - fieldValue = value != null ? value.ToString() : string.Empty; + var p = UmbracoContext.Current.ContentCache.GetById(nodeId.GetValueOrDefault()); + var v = p.GetPropertyValue(field); + fieldValue = v == null ? string.Empty : v.ToString(); } } else diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index 4737ab74e5..de8f96b593 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -528,6 +528,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { IPublishedProperty property; + // must ignore that one + if (i.Key == "version") continue; + if (i.Key.InvariantStartsWith("__")) { // no type for that one, dunno how to convert diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 47c03697f3..c620394f00 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -1651,6 +1651,12 @@ namespace Umbraco.Web return contents.Where(x => types.Contains(x.DocumentTypeAlias.ToLowerInvariant())); } + public static T OfType(this IPublishedContent content) + where T : class, IPublishedContent + { + return content as T; + } + #endregion #region PropertyAliasesAndNames diff --git a/src/Umbraco.Web/Routing/PublishedContentRequest.cs b/src/Umbraco.Web/Routing/PublishedContentRequest.cs index 1ee01a72ab..655da398bb 100644 --- a/src/Umbraco.Web/Routing/PublishedContentRequest.cs +++ b/src/Umbraco.Web/Routing/PublishedContentRequest.cs @@ -380,7 +380,7 @@ namespace Umbraco.Web.Routing get { if (_umbracoPage == null) - throw new InvalidOperationException("The umbraco page object is only available once Finalize()"); + throw new InvalidOperationException("The UmbracoPage object has not been initialized yet."); return _umbracoPage; } diff --git a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs index fb6aca88b3..106f385440 100644 --- a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs +++ b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs @@ -95,13 +95,20 @@ namespace Umbraco.Web.Routing // can't go beyond that point without a PublishedContent to render // it's ok not to have a template, in order to give MVC a chance to hijack routes - // assign the legacy page back to the docrequest - // handlers like default.aspx will want it and most macros currently need it - _pcr.UmbracoPage = new page(_pcr); + // note - the page() ctor below will cause the "page" to get the value of all its + // "elements" ie of all the IPublishedContent property. If we use the object value, + // that will trigger macro execution - which can't happen because macro execution + // requires that _pcr.UmbracoPage is already initialized = catch-22. The "legacy" + // pipeline did _not_ evaluate the macros, ie it is using the data value, and we + // have to keep doing it because of that catch-22. - // these two are used by many legacy objects - _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; - _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; + // assign the legacy page back to the docrequest + // handlers like default.aspx will want it and most macros currently need it + _pcr.UmbracoPage = new page(_pcr); + + // used by many legacy objects + _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; + _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; } /// @@ -138,6 +145,8 @@ namespace Umbraco.Web.Routing return; } + // see note in PrepareRequest() + // assign the legacy page back to the docrequest // handlers like default.aspx will want it and most macros currently need it _pcr.UmbracoPage = new page(_pcr); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index eadfedc688..ef4460e0df 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -536,6 +536,7 @@ + ASPXCodeBehind diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index b46fad1b09..3845d35c5d 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Xml; using Umbraco.Web.Models; using Umbraco.Web.PublishedCache; +using Umbraco.Web.Routing; using Umbraco.Web.Templates; using umbraco; using System.Collections.Generic; @@ -484,6 +485,17 @@ namespace Umbraco.Web return UmbracoContext.Current.UrlProvider.GetUrl(contentId); } + /// + /// Gets the url of a content identified by its identifier, in a specified mode. + /// + /// The content identifier. + /// The mode. + /// The url for the content. + public string Url(int contentId, UrlProviderMode mode) + { + return UmbracoContext.Current.UrlProvider.GetUrl(contentId, mode); + } + /// /// This method will always add the domain to the path if the hostnames are set up correctly. /// diff --git a/src/Umbraco.Web/umbraco.presentation/CompatibilityHelper.cs b/src/Umbraco.Web/umbraco.presentation/CompatibilityHelper.cs new file mode 100644 index 0000000000..90674a0d4b --- /dev/null +++ b/src/Umbraco.Web/umbraco.presentation/CompatibilityHelper.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Web; +using Umbraco.Core.Models; +using umbraco.interfaces; + +namespace Umbraco.Web.umbraco.presentation +{ + static class CompatibilityHelper + { + // NOTE - this is all already in umbraco.MacroEngines + // which references Umbraco.Web - so we can't reference it without + // creating circular references + // fixme - there has to be a better way? + + public static INode ConvertToNode(IPublishedContent doc) + { + var node = new ConvertedNode(doc); + return node; + } + + public static IProperty ConvertToNodeProperty(IPublishedProperty prop) + { + return new ConvertedProperty(prop.PropertyTypeAlias, prop.Value.ToString()); + } + + private class ConvertedNode : INode + { + private readonly IPublishedContent _doc; + + public ConvertedNode(IPublishedContent doc) + { + _doc = doc; + + if (doc == null) + { + Id = 0; + return; + } + + template = doc.TemplateId; + Id = doc.Id; + Path = doc.Path; + CreatorName = doc.CreatorName; + SortOrder = doc.SortOrder; + UpdateDate = doc.UpdateDate; + Name = doc.Name; + NodeTypeAlias = doc.DocumentTypeAlias; + CreateDate = doc.CreateDate; + CreatorID = doc.CreatorId; + Level = doc.Level; + UrlName = doc.UrlName; + Version = doc.Version; + WriterID = doc.WriterId; + WriterName = doc.WriterName; + } + + public INode Parent + { + get { return ConvertToNode(_doc.Parent); } + } + public int Id { get; private set; } + public int template { get; private set; } + public int SortOrder { get; private set; } + public string Name { get; private set; } + public string UrlName { get; private set; } + public string NodeTypeAlias { get; private set; } + public string WriterName { get; private set; } + public string CreatorName { get; private set; } + public int WriterID { get; private set; } + public int CreatorID { get; private set; } + public string Path { get; private set; } + public DateTime CreateDate { get; private set; } + public DateTime UpdateDate { get; private set; } + public Guid Version { get; private set; } + + public string NiceUrl + { + get { return _doc.Url; } + } + + public string Url + { + get { return _doc.Url; } + } + + public int Level { get; private set; } + public List PropertiesAsList + { + get { return _doc.Properties.Select(ConvertToNodeProperty).ToList(); } + } + public List ChildrenAsList + { + get { return _doc.Children.Select(ConvertToNode).ToList(); } + } + public IProperty GetProperty(string Alias) + { + return PropertiesAsList.Cast().FirstOrDefault(p => p.Alias == Alias); + } + + public IProperty GetProperty(string Alias, out bool propertyExists) + { + foreach (var p in from global::umbraco.NodeFactory.Property p in PropertiesAsList where p.Alias == Alias select p) + { + propertyExists = true; + return p; + } + propertyExists = false; + return null; + } + + public DataTable ChildrenAsTable() + { + return _doc.ChildrenAsTable(); + } + + public DataTable ChildrenAsTable(string nodeTypeAliasFilter) + { + return _doc.ChildrenAsTable(nodeTypeAliasFilter); + } + } + + private class ConvertedProperty : IProperty, IHtmlString + { + private readonly string _alias; + private readonly string _value; + + public ConvertedProperty(string alias, string value) + { + _alias = alias; + _value = value; + } + + public string Alias + { + get { return _alias; } + } + + public string Value + { + get { return _value; } + } + + public Guid Version + { + get { return Guid.Empty; } + } + + public bool IsNull() + { + return Value == null; + } + + public bool HasValue() + { + return !string.IsNullOrWhiteSpace(Value); + } + + public int ContextId { get; set; } + public string ContextAlias { get; set; } + + // implements IHtmlString.ToHtmlString + public string ToHtmlString() + { + return Value; + } + } + } +} diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index e069dbb70b..630480fcdc 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -35,6 +35,7 @@ using umbraco.cms.businesslogic.member; using umbraco.DataLayer; using umbraco.NodeFactory; using umbraco.presentation.templateControls; +using Umbraco.Web.umbraco.presentation; using Content = umbraco.cms.businesslogic.Content; using Macro = umbraco.cms.businesslogic.macro.Macro; using MacroErrorEventArgs = Umbraco.Core.Events.MacroErrorEventArgs; @@ -1334,7 +1335,7 @@ namespace umbraco IMacroEngine engine = null; engine = MacroEngineFactory.GetEngine(PartialViewMacroEngine.EngineName); - var ret = engine.Execute(macro, Node.GetCurrent()); + var ret = engine.Execute(macro, CompatibilityHelper.ConvertToNode(UmbracoContext.Current.PublishedContentRequest.PublishedContent)); // if the macro engine supports success reporting and executing failed, then return an empty control so it's not cached if (engine is IMacroEngineResultStatus) @@ -1359,13 +1360,13 @@ namespace umbraco engine = MacroEngineFactory.GetByExtension(macro.ScriptLanguage); ret = engine.Execute( macro, - Node.GetCurrent()); + CompatibilityHelper.ConvertToNode(UmbracoContext.Current.PublishedContentRequest.PublishedContent)); } else { string path = IOHelper.MapPath(SystemDirectories.MacroScripts + "/" + macro.ScriptName); engine = MacroEngineFactory.GetByFilename(path); - ret = engine.Execute(macro, Node.GetCurrent()); + ret = engine.Execute(macro, CompatibilityHelper.ConvertToNode(UmbracoContext.Current.PublishedContentRequest.PublishedContent)); } // if the macro engine supports success reporting and executing failed, then return an empty control so it's not cached diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index 18c5785a87..6f933ddbd3 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -286,9 +286,17 @@ namespace umbraco { foreach(var p in node.Properties) { - if (!_elements.ContainsKey(p.PropertyTypeAlias)) + if (_elements.ContainsKey(p.PropertyTypeAlias) == false) { - _elements[p.PropertyTypeAlias] = p.Value; + // note: legacy used the raw value (see populating from an Xml node below) + // so we're doing the same here, using DataValue. If we use Value then every + // value will be converted NOW - including RTEs that may contain macros that + // require that the 'page' is already initialized = catch-22. + + // to properly fix this, we'd need to turn the elements collection into some + // sort of collection of lazy values. + + _elements[p.PropertyTypeAlias] = p.DataValue; } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs index db5046d196..504ca21538 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs @@ -11,6 +11,7 @@ using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.propertytype; using umbraco.interfaces; using Umbraco.Core; +using Umbraco.Web; namespace umbraco.NodeFactory { @@ -542,11 +543,10 @@ namespace umbraco.NodeFactory public static int getCurrentNodeId() { - XmlNode n = ((IHasXmlNode)library.GetXmlNodeCurrent().Current).GetNode(); - if (n.Attributes == null || n.Attributes.GetNamedItem("id") == null) - throw new ArgumentException("Current node is null. This might be due to previewing an unpublished node. As the NodeFactory works with published data, macros using the node factory won't work in preview mode.", "Current node is " + System.Web.HttpContext.Current.Items["pageID"].ToString()); - - return int.Parse(n.Attributes.GetNamedItem("id").Value); + if (UmbracoContext.Current == null) throw new InvalidOperationException("Cannot get current node id without an UmbracoContext."); + if (UmbracoContext.Current.PublishedContentRequest == null) throw new InvalidOperationException("Cannot get current node id without a PublishedContentRequest."); + if (UmbracoContext.Current.PublishedContentRequest.HasPublishedContent == false) throw new InvalidOperationException("Cannot get current node id because the current PublishedContentRequest has no content."); + return UmbracoContext.Current.PublishedContentRequest.PublishedContent.Id; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs index 9904e9283d..f2e823a33d 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs @@ -13,6 +13,7 @@ using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Xml; using System.IO; +using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; using umbraco.cms.businesslogic.web; @@ -96,7 +97,8 @@ namespace umbraco.presentation.preview //Inject preview xml parentId = document.Level == 1 ? -1 : document.Parent.Id; var previewXml = document.ToPreviewXml(XmlContent); - if (document.HasPendingChanges()) // HasPendingChanges is obsolete but what's the equivalent that wouldn't hit the DB? + if (document.Content.Published == false + && ApplicationContext.Current.Services.ContentService.HasPublishedVersion(document.Id)) previewXml.Attributes.Append(XmlContent.CreateAttribute("isDraft")); content.AppendDocumentXml(document.Id, document.Level, parentId, previewXml, XmlContent); } diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicBackingItem.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicBackingItem.cs index 0362095d4f..e2a7c6d56f 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicBackingItem.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicBackingItem.cs @@ -6,9 +6,11 @@ using umbraco.interfaces; using umbraco.cms.businesslogic.media; using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.property; -using umbraco.presentation.nodeFactory; using System.Data; using Umbraco.Core; +using umbraco.MacroEngines.Library; +using Umbraco.Web; +using Umbraco.Web.umbraco.presentation; namespace umbraco.MacroEngines { @@ -30,11 +32,11 @@ namespace umbraco.MacroEngines } public DynamicBackingItem(int Id) { - NodeFactory.Node baseNode = new NodeFactory.Node(Id); + var n = UmbracoContext.Current.ContentCache.GetById(Id).ConvertToNode(); - this.content = baseNode; + this.content = n; this.Type = DynamicBackingItemType.Content; - if (baseNode.Id == 0 && Id != 0) + if (n.Id == 0 && Id != 0) { this.media = ExamineBackedMedia.GetUmbracoMedia(Id); this.Type = DynamicBackingItemType.Media; @@ -48,7 +50,6 @@ namespace umbraco.MacroEngines } public DynamicBackingItem(int Id, DynamicBackingItemType Type) { - NodeFactory.Node baseNode = new NodeFactory.Node(Id); if (Type == DynamicBackingItemType.Media) { this.media = ExamineBackedMedia.GetUmbracoMedia(Id); @@ -56,7 +57,7 @@ namespace umbraco.MacroEngines } else { - this.content = baseNode; + this.content = UmbracoContext.Current.ContentCache.GetById(Id).ConvertToNode(); this.Type = Type; } } diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/PublishedContentExtensions.cs b/src/umbraco.MacroEngines/RazorDynamicNode/PublishedContentExtensions.cs index cf5180d5e1..59b32fa0ea 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/PublishedContentExtensions.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/PublishedContentExtensions.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models; using Umbraco.Web; using umbraco.NodeFactory; using umbraco.interfaces; +using Umbraco.Web.umbraco.presentation; using Property = umbraco.NodeFactory.Property; namespace umbraco.MacroEngines.Library @@ -18,107 +19,9 @@ namespace umbraco.MacroEngines.Library /// These are dedicated to converting DynamicPublishedContent to INode. internal static class PublishedContentExtensions { - internal static IProperty ConvertToNodeProperty(this IPublishedProperty prop) - { - return new PropertyResult(prop.PropertyTypeAlias, prop.Value.ToString()); - } - internal static INode ConvertToNode(this IPublishedContent doc) { - var node = new ConvertedNode(doc); - return node; - } - - /// - /// Internal custom INode class used for conversions from DynamicPublishedContent. - /// - private class ConvertedNode : INode - { - private readonly IPublishedContent _doc; - - public ConvertedNode(IPublishedContent doc) - { - _doc = doc; - template = doc.TemplateId; - Id = doc.Id; - Path = doc.Path; - CreatorName = doc.CreatorName; - SortOrder = doc.SortOrder; - UpdateDate = doc.UpdateDate; - Name = doc.Name; - NodeTypeAlias = doc.DocumentTypeAlias; - CreateDate = doc.CreateDate; - CreatorID = doc.CreatorId; - Level = doc.Level; - UrlName = doc.UrlName; - Version = doc.Version; - WriterID = doc.WriterId; - WriterName = doc.WriterName; - } - - public INode Parent - { - get { return _doc.Parent.ConvertToNode(); } - } - public int Id { get; private set; } - public int template { get; private set; } - public int SortOrder { get; private set; } - public string Name { get; private set; } - public string UrlName { get; private set; } - public string NodeTypeAlias { get; private set; } - public string WriterName { get; private set; } - public string CreatorName { get; private set; } - public int WriterID { get; private set; } - public int CreatorID { get; private set; } - public string Path { get; private set; } - public DateTime CreateDate { get; private set; } - public DateTime UpdateDate { get; private set; } - public Guid Version { get; private set; } - - public string NiceUrl - { - get { return library.NiceUrl(Id); } - } - - public string Url - { - get { return library.NiceUrl(Id); } - } - - public int Level { get; private set; } - public List PropertiesAsList - { - get { return _doc.Properties.Select(ConvertToNodeProperty).ToList(); } - } - public List ChildrenAsList - { - get { return _doc.Children.Select(x => x.ConvertToNode()).ToList(); } - } - public IProperty GetProperty(string Alias) - { - return PropertiesAsList.Cast().FirstOrDefault(p => p.Alias == Alias); - } - - public IProperty GetProperty(string Alias, out bool propertyExists) - { - foreach (var p in from Property p in PropertiesAsList where p.Alias == Alias select p) - { - propertyExists = true; - return p; - } - propertyExists = false; - return null; - } - - public DataTable ChildrenAsTable() - { - return _doc.ChildrenAsTable(); - } - - public DataTable ChildrenAsTable(string nodeTypeAliasFilter) - { - return _doc.ChildrenAsTable(nodeTypeAliasFilter); - } + return CompatibilityHelper.ConvertToNode(doc); } } } \ No newline at end of file