diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
index 4a00aeb3ee..2dcbe06458 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
@@ -1,146 +1,141 @@
-using System.Collections.Generic;
-using System.Configuration;
-using Umbraco.Core.Macros;
-
-namespace Umbraco.Core.Configuration.UmbracoSettings
-{
- internal class ContentElement : UmbracoConfigurationElement, IContentSection
- {
- private const string DefaultPreviewBadge = @"In Preview Mode - click to end";
-
- [ConfigurationProperty("imaging")]
- internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
-
- [ConfigurationProperty("scripteditor")]
- internal ContentScriptEditorElement ScriptEditor => (ContentScriptEditorElement) this["scripteditor"];
-
- [ConfigurationProperty("ResolveUrlsFromTextString")]
- internal InnerTextConfigurationElement ResolveUrlsFromTextString => GetOptionalTextElement("ResolveUrlsFromTextString", false);
-
- [ConfigurationProperty("UploadAllowDirectories")]
- internal InnerTextConfigurationElement UploadAllowDirectories => GetOptionalTextElement("UploadAllowDirectories", true);
-
- public IEnumerable Error404Collection => Errors.Error404Collection;
-
- [ConfigurationProperty("errors", IsRequired = true)]
- internal ContentErrorsElement Errors => (ContentErrorsElement) base["errors"];
-
- [ConfigurationProperty("notifications", IsRequired = true)]
- internal NotificationsElement Notifications => (NotificationsElement) base["notifications"];
-
- [ConfigurationProperty("ensureUniqueNaming")]
- internal InnerTextConfigurationElement EnsureUniqueNaming => GetOptionalTextElement("ensureUniqueNaming", true);
-
- [ConfigurationProperty("XmlCacheEnabled")]
- internal InnerTextConfigurationElement XmlCacheEnabled => GetOptionalTextElement("XmlCacheEnabled", true);
-
- [ConfigurationProperty("ContinouslyUpdateXmlDiskCache")]
- internal InnerTextConfigurationElement ContinouslyUpdateXmlDiskCache => GetOptionalTextElement("ContinouslyUpdateXmlDiskCache", true);
-
- [ConfigurationProperty("XmlContentCheckForDiskChanges")]
- internal InnerTextConfigurationElement XmlContentCheckForDiskChanges => GetOptionalTextElement("XmlContentCheckForDiskChanges", false);
-
- [ConfigurationProperty("EnableSplashWhileLoading")]
- internal InnerTextConfigurationElement EnableSplashWhileLoading => GetOptionalTextElement("EnableSplashWhileLoading", false);
-
- [ConfigurationProperty("PropertyContextHelpOption")]
- internal InnerTextConfigurationElement PropertyContextHelpOption => GetOptionalTextElement("PropertyContextHelpOption", "text");
-
- [ConfigurationProperty("ForceSafeAliases")]
- internal InnerTextConfigurationElement ForceSafeAliases => GetOptionalTextElement("ForceSafeAliases", true);
-
- [ConfigurationProperty("PreviewBadge")]
- internal InnerTextConfigurationElement PreviewBadge => GetOptionalTextElement("PreviewBadge", DefaultPreviewBadge);
-
- [ConfigurationProperty("UmbracoLibraryCacheDuration")]
- internal InnerTextConfigurationElement UmbracoLibraryCacheDuration => GetOptionalTextElement("UmbracoLibraryCacheDuration", 1800);
-
- [ConfigurationProperty("MacroErrors")]
- internal InnerTextConfigurationElement MacroErrors => GetOptionalTextElement("MacroErrors", MacroErrorBehaviour.Inline);
-
- [ConfigurationProperty("disallowedUploadFiles")]
- internal CommaDelimitedConfigurationElement DisallowedUploadFiles => GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"});
-
- [ConfigurationProperty("allowedUploadFiles")]
- internal CommaDelimitedConfigurationElement AllowedUploadFiles => GetOptionalDelimitedElement("allowedUploadFiles", new string[0]);
-
- [ConfigurationProperty("cloneXmlContent")]
- internal InnerTextConfigurationElement CloneXmlContent => GetOptionalTextElement("cloneXmlContent", true);
-
- [ConfigurationProperty("GlobalPreviewStorageEnabled")]
- internal InnerTextConfigurationElement GlobalPreviewStorageEnabled => GetOptionalTextElement("GlobalPreviewStorageEnabled", false);
-
- [ConfigurationProperty("defaultDocumentTypeProperty")]
- internal InnerTextConfigurationElement DefaultDocumentTypeProperty => GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring");
-
- [ConfigurationProperty("showDeprecatedPropertyEditors")]
- internal InnerTextConfigurationElement ShowDeprecatedPropertyEditors => GetOptionalTextElement("showDeprecatedPropertyEditors", false);
-
- [ConfigurationProperty("EnableInheritedDocumentTypes")]
- internal InnerTextConfigurationElement EnableInheritedDocumentTypes => GetOptionalTextElement("EnableInheritedDocumentTypes", true);
-
- [ConfigurationProperty("EnableInheritedMediaTypes")]
- internal InnerTextConfigurationElement EnableInheritedMediaTypes => GetOptionalTextElement("EnableInheritedMediaTypes", true);
-
- [ConfigurationProperty("loginBackgroundImage")]
- internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty);
-
- string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress;
-
- bool IContentSection.DisableHtmlEmail => Notifications.DisableHtmlEmail;
-
- IEnumerable IContentSection.ImageFileTypes => Imaging.ImageFileTypes;
-
- IEnumerable IContentSection.ImageTagAllowedAttributes => Imaging.ImageTagAllowedAttributes;
-
- IEnumerable IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
-
- bool IContentSection.ScriptEditorDisable => ScriptEditor.ScriptEditorDisable;
-
- string IContentSection.ScriptFolderPath => ScriptEditor.ScriptFolderPath;
-
- IEnumerable IContentSection.ScriptFileTypes => ScriptEditor.ScriptFileTypes;
-
- bool IContentSection.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
-
- bool IContentSection.UploadAllowDirectories => UploadAllowDirectories;
-
- bool IContentSection.EnsureUniqueNaming => EnsureUniqueNaming;
-
- bool IContentSection.XmlCacheEnabled => XmlCacheEnabled;
-
- bool IContentSection.ContinouslyUpdateXmlDiskCache => ContinouslyUpdateXmlDiskCache;
-
- bool IContentSection.XmlContentCheckForDiskChanges => XmlContentCheckForDiskChanges;
-
- bool IContentSection.EnableSplashWhileLoading => EnableSplashWhileLoading;
-
- string IContentSection.PropertyContextHelpOption => PropertyContextHelpOption;
-
- bool IContentSection.ForceSafeAliases => ForceSafeAliases;
-
- string IContentSection.PreviewBadge => PreviewBadge;
-
- int IContentSection.UmbracoLibraryCacheDuration => UmbracoLibraryCacheDuration;
-
- MacroErrorBehaviour IContentSection.MacroErrorBehaviour => MacroErrors;
-
- IEnumerable IContentSection.DisallowedUploadFiles => DisallowedUploadFiles;
-
- IEnumerable IContentSection.AllowedUploadFiles => AllowedUploadFiles;
-
- bool IContentSection.CloneXmlContent => CloneXmlContent;
-
- bool IContentSection.GlobalPreviewStorageEnabled => GlobalPreviewStorageEnabled;
-
- string IContentSection.DefaultDocumentTypeProperty => DefaultDocumentTypeProperty;
-
- bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
-
- bool IContentSection.EnableInheritedDocumentTypes => EnableInheritedDocumentTypes;
-
- bool IContentSection.EnableInheritedMediaTypes => EnableInheritedMediaTypes;
-
- string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
- }
-}
+using System.Collections.Generic;
+using System.Configuration;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Core.Configuration.UmbracoSettings
+{
+ internal class ContentElement : UmbracoConfigurationElement, IContentSection
+ {
+ private const string DefaultPreviewBadge = @"In Preview Mode - click to end";
+
+ [ConfigurationProperty("imaging")]
+ internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
+
+ [ConfigurationProperty("scripteditor")]
+ internal ContentScriptEditorElement ScriptEditor => (ContentScriptEditorElement) this["scripteditor"];
+
+ [ConfigurationProperty("ResolveUrlsFromTextString")]
+ internal InnerTextConfigurationElement ResolveUrlsFromTextString => GetOptionalTextElement("ResolveUrlsFromTextString", false);
+
+ [ConfigurationProperty("UploadAllowDirectories")]
+ internal InnerTextConfigurationElement UploadAllowDirectories => GetOptionalTextElement("UploadAllowDirectories", true);
+
+ public IEnumerable Error404Collection => Errors.Error404Collection;
+
+ [ConfigurationProperty("errors", IsRequired = true)]
+ internal ContentErrorsElement Errors => (ContentErrorsElement) base["errors"];
+
+ [ConfigurationProperty("notifications", IsRequired = true)]
+ internal NotificationsElement Notifications => (NotificationsElement) base["notifications"];
+
+ [ConfigurationProperty("ensureUniqueNaming")]
+ internal InnerTextConfigurationElement EnsureUniqueNaming => GetOptionalTextElement("ensureUniqueNaming", true);
+
+ [ConfigurationProperty("XmlCacheEnabled")]
+ internal InnerTextConfigurationElement XmlCacheEnabled => GetOptionalTextElement("XmlCacheEnabled", true);
+
+ [ConfigurationProperty("ContinouslyUpdateXmlDiskCache")]
+ internal InnerTextConfigurationElement ContinouslyUpdateXmlDiskCache => GetOptionalTextElement("ContinouslyUpdateXmlDiskCache", true);
+
+ [ConfigurationProperty("XmlContentCheckForDiskChanges")]
+ internal InnerTextConfigurationElement XmlContentCheckForDiskChanges => GetOptionalTextElement("XmlContentCheckForDiskChanges", false);
+
+ [ConfigurationProperty("EnableSplashWhileLoading")]
+ internal InnerTextConfigurationElement EnableSplashWhileLoading => GetOptionalTextElement("EnableSplashWhileLoading", false);
+
+ [ConfigurationProperty("PropertyContextHelpOption")]
+ internal InnerTextConfigurationElement PropertyContextHelpOption => GetOptionalTextElement("PropertyContextHelpOption", "text");
+
+ [ConfigurationProperty("ForceSafeAliases")]
+ internal InnerTextConfigurationElement ForceSafeAliases => GetOptionalTextElement("ForceSafeAliases", true);
+
+ [ConfigurationProperty("PreviewBadge")]
+ internal InnerTextConfigurationElement PreviewBadge => GetOptionalTextElement("PreviewBadge", DefaultPreviewBadge);
+
+ [ConfigurationProperty("MacroErrors")]
+ internal InnerTextConfigurationElement MacroErrors => GetOptionalTextElement("MacroErrors", MacroErrorBehaviour.Inline);
+
+ [ConfigurationProperty("disallowedUploadFiles")]
+ internal CommaDelimitedConfigurationElement DisallowedUploadFiles => GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"});
+
+ [ConfigurationProperty("allowedUploadFiles")]
+ internal CommaDelimitedConfigurationElement AllowedUploadFiles => GetOptionalDelimitedElement("allowedUploadFiles", new string[0]);
+
+ [ConfigurationProperty("cloneXmlContent")]
+ internal InnerTextConfigurationElement CloneXmlContent => GetOptionalTextElement("cloneXmlContent", true);
+
+ [ConfigurationProperty("GlobalPreviewStorageEnabled")]
+ internal InnerTextConfigurationElement GlobalPreviewStorageEnabled => GetOptionalTextElement("GlobalPreviewStorageEnabled", false);
+
+ [ConfigurationProperty("defaultDocumentTypeProperty")]
+ internal InnerTextConfigurationElement DefaultDocumentTypeProperty => GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring");
+
+ [ConfigurationProperty("showDeprecatedPropertyEditors")]
+ internal InnerTextConfigurationElement ShowDeprecatedPropertyEditors => GetOptionalTextElement("showDeprecatedPropertyEditors", false);
+
+ [ConfigurationProperty("EnableInheritedDocumentTypes")]
+ internal InnerTextConfigurationElement EnableInheritedDocumentTypes => GetOptionalTextElement("EnableInheritedDocumentTypes", true);
+
+ [ConfigurationProperty("EnableInheritedMediaTypes")]
+ internal InnerTextConfigurationElement EnableInheritedMediaTypes => GetOptionalTextElement("EnableInheritedMediaTypes", true);
+
+ [ConfigurationProperty("loginBackgroundImage")]
+ internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty);
+
+ string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress;
+
+ bool IContentSection.DisableHtmlEmail => Notifications.DisableHtmlEmail;
+
+ IEnumerable IContentSection.ImageFileTypes => Imaging.ImageFileTypes;
+
+ IEnumerable IContentSection.ImageTagAllowedAttributes => Imaging.ImageTagAllowedAttributes;
+
+ IEnumerable IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
+
+ bool IContentSection.ScriptEditorDisable => ScriptEditor.ScriptEditorDisable;
+
+ string IContentSection.ScriptFolderPath => ScriptEditor.ScriptFolderPath;
+
+ IEnumerable IContentSection.ScriptFileTypes => ScriptEditor.ScriptFileTypes;
+
+ bool IContentSection.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
+
+ bool IContentSection.UploadAllowDirectories => UploadAllowDirectories;
+
+ bool IContentSection.EnsureUniqueNaming => EnsureUniqueNaming;
+
+ bool IContentSection.XmlCacheEnabled => XmlCacheEnabled;
+
+ bool IContentSection.ContinouslyUpdateXmlDiskCache => ContinouslyUpdateXmlDiskCache;
+
+ bool IContentSection.XmlContentCheckForDiskChanges => XmlContentCheckForDiskChanges;
+
+ bool IContentSection.EnableSplashWhileLoading => EnableSplashWhileLoading;
+
+ string IContentSection.PropertyContextHelpOption => PropertyContextHelpOption;
+
+ bool IContentSection.ForceSafeAliases => ForceSafeAliases;
+
+ string IContentSection.PreviewBadge => PreviewBadge;
+
+ MacroErrorBehaviour IContentSection.MacroErrorBehaviour => MacroErrors;
+
+ IEnumerable IContentSection.DisallowedUploadFiles => DisallowedUploadFiles;
+
+ IEnumerable IContentSection.AllowedUploadFiles => AllowedUploadFiles;
+
+ bool IContentSection.CloneXmlContent => CloneXmlContent;
+
+ bool IContentSection.GlobalPreviewStorageEnabled => GlobalPreviewStorageEnabled;
+
+ string IContentSection.DefaultDocumentTypeProperty => DefaultDocumentTypeProperty;
+
+ bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
+
+ bool IContentSection.EnableInheritedDocumentTypes => EnableInheritedDocumentTypes;
+
+ bool IContentSection.EnableInheritedMediaTypes => EnableInheritedMediaTypes;
+
+ string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
index 6929646114..7f6f57f4cf 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
@@ -1,72 +1,70 @@
-using System.Collections.Generic;
-using Umbraco.Core.Macros;
-
-namespace Umbraco.Core.Configuration.UmbracoSettings
-{
- public interface IContentSection : IUmbracoConfigurationSection
- {
- string NotificationEmailAddress { get; }
-
- bool DisableHtmlEmail { get; }
-
- IEnumerable ImageFileTypes { get; }
-
- IEnumerable ImageTagAllowedAttributes { get; }
-
- IEnumerable ImageAutoFillProperties { get; }
-
- string ScriptFolderPath { get; }
-
- IEnumerable ScriptFileTypes { get; }
-
- bool ScriptEditorDisable { get; }
-
- bool ResolveUrlsFromTextString { get; }
-
+using System.Collections.Generic;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Core.Configuration.UmbracoSettings
+{
+ public interface IContentSection : IUmbracoConfigurationSection
+ {
+ string NotificationEmailAddress { get; }
+
+ bool DisableHtmlEmail { get; }
+
+ IEnumerable ImageFileTypes { get; }
+
+ IEnumerable ImageTagAllowedAttributes { get; }
+
+ IEnumerable ImageAutoFillProperties { get; }
+
+ string ScriptFolderPath { get; }
+
+ IEnumerable ScriptFileTypes { get; }
+
+ bool ScriptEditorDisable { get; }
+
+ bool ResolveUrlsFromTextString { get; }
+
bool UploadAllowDirectories { get; }
- IEnumerable Error404Collection { get; }
-
- bool EnsureUniqueNaming { get; }
-
- bool XmlCacheEnabled { get; }
-
- bool ContinouslyUpdateXmlDiskCache { get; }
-
- bool XmlContentCheckForDiskChanges { get; }
-
- bool EnableSplashWhileLoading { get; }
-
- string PropertyContextHelpOption { get; }
-
- bool ForceSafeAliases { get; }
-
- string PreviewBadge { get; }
-
- int UmbracoLibraryCacheDuration { get; }
-
- MacroErrorBehaviour MacroErrorBehaviour { get; }
-
- IEnumerable DisallowedUploadFiles { get; }
-
- IEnumerable AllowedUploadFiles { get; }
-
- bool CloneXmlContent { get; }
-
- bool GlobalPreviewStorageEnabled { get; }
-
- string DefaultDocumentTypeProperty { get; }
-
- ///
- /// Gets a value indicating whether to show deprecated property editors in
- /// a datatype list of available editors.
- ///
- bool ShowDeprecatedPropertyEditors { get; }
-
- bool EnableInheritedDocumentTypes { get; }
-
- bool EnableInheritedMediaTypes { get; }
-
- string LoginBackgroundImage { get; }
- }
-}
+ IEnumerable Error404Collection { get; }
+
+ bool EnsureUniqueNaming { get; }
+
+ bool XmlCacheEnabled { get; }
+
+ bool ContinouslyUpdateXmlDiskCache { get; }
+
+ bool XmlContentCheckForDiskChanges { get; }
+
+ bool EnableSplashWhileLoading { get; }
+
+ string PropertyContextHelpOption { get; }
+
+ bool ForceSafeAliases { get; }
+
+ string PreviewBadge { get; }
+
+ MacroErrorBehaviour MacroErrorBehaviour { get; }
+
+ IEnumerable DisallowedUploadFiles { get; }
+
+ IEnumerable AllowedUploadFiles { get; }
+
+ bool CloneXmlContent { get; }
+
+ bool GlobalPreviewStorageEnabled { get; }
+
+ string DefaultDocumentTypeProperty { get; }
+
+ ///
+ /// Gets a value indicating whether to show deprecated property editors in
+ /// a datatype list of available editors.
+ ///
+ bool ShowDeprecatedPropertyEditors { get; }
+
+ bool EnableInheritedDocumentTypes { get; }
+
+ bool EnableInheritedMediaTypes { get; }
+
+ string LoginBackgroundImage { get; }
+ }
+}
diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs
index 0980b600e8..fe32a43cc9 100644
--- a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs
+++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs
@@ -1,204 +1,199 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using NUnit.Framework;
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.Macros;
-
-namespace Umbraco.Tests.Configurations.UmbracoSettings
-{
- [TestFixture]
- public class ContentElementTests : UmbracoSettingsTests
- {
- [Test]
- public void EmailAddress()
- {
- Assert.IsTrue(SettingsSection.Content.NotificationEmailAddress == "robot@umbraco.dk");
- }
- [Test]
- public virtual void DisableHtmlEmail()
- {
- Assert.IsTrue(SettingsSection.Content.DisableHtmlEmail == true);
- }
-
- [Test]
- public virtual void Can_Set_Multiple()
- {
- Assert.IsTrue(SettingsSection.Content.Error404Collection.Count() == 3);
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).Culture == "default");
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId == 1047);
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId);
- Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey);
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).Culture == "en-US");
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath == "$site/error [@name = 'error']");
- Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId);
- Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey);
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).Culture == "en-UK");
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey == new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"));
- Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey);
- Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId);
- }
-
- [Test]
- public void ScriptFolderPath()
- {
- Assert.IsTrue(SettingsSection.Content.ScriptFolderPath == "/scripts");
- }
- [Test]
- public void ScriptFileTypes()
- {
- Assert.IsTrue(SettingsSection.Content.ScriptFileTypes.All(x => "js,xml".Split(',').Contains(x)));
- }
- [Test]
- public void DisableScriptEditor()
- {
- Assert.IsTrue(SettingsSection.Content.ScriptEditorDisable == false);
- }
-
- [Test]
- public void ImageFileTypes()
- {
- Assert.IsTrue(SettingsSection.Content.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x)));
- }
- [Test]
- public void AllowedAttributes()
- {
- Assert.IsTrue(SettingsSection.Content.ImageTagAllowedAttributes.All(x => "src,alt,border,class,style,align,id,name,onclick,usemap".Split(',').Contains(x)));
- }
- [Test]
- public virtual void ImageAutoFillProperties()
- {
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.Count() == 2);
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias == "umbracoFile");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias == "umbracoWidth");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias == "umbracoHeight");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias == "umbracoBytes");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias == "umbracoExtension");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).Alias == "umbracoFile2");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias == "umbracoWidth2");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias == "umbracoHeight2");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias == "umbracoBytes2");
- Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias == "umbracoExtension2");
- }
-
- [Test]
- public void UploadAllowDirectories()
- {
- Assert.IsTrue(SettingsSection.Content.UploadAllowDirectories == true);
- }
- [Test]
- public void DefaultDocumentTypeProperty()
- {
- Assert.IsTrue(SettingsSection.Content.DefaultDocumentTypeProperty == "Textstring");
- }
- [Test]
- public void GlobalPreviewStorageEnabled()
- {
- Assert.IsTrue(SettingsSection.Content.GlobalPreviewStorageEnabled == false);
- }
- [Test]
- public void CloneXmlContent()
- {
- Assert.IsTrue(SettingsSection.Content.CloneXmlContent == true);
- }
- [Test]
- public void EnsureUniqueNaming()
- {
- Assert.IsTrue(SettingsSection.Content.EnsureUniqueNaming == true);
- }
-
-
- [Test]
- public void ForceSafeAliases()
- {
- Assert.IsTrue(SettingsSection.Content.ForceSafeAliases == true);
- }
- [Test]
- public void XmlCacheEnabled()
- {
- Assert.IsTrue(SettingsSection.Content.XmlCacheEnabled == true);
- }
- [Test]
- public void ContinouslyUpdateXmlDiskCache()
- {
- Assert.IsTrue(SettingsSection.Content.ContinouslyUpdateXmlDiskCache == true);
- }
- [Test]
- public virtual void XmlContentCheckForDiskChanges()
- {
- Assert.IsTrue(SettingsSection.Content.XmlContentCheckForDiskChanges == true);
- }
- [Test]
- public void EnableSplashWhileLoading()
- {
- Assert.IsTrue(SettingsSection.Content.EnableSplashWhileLoading == false);
- }
- [Test]
- public void PropertyContextHelpOption()
- {
- Assert.IsTrue(SettingsSection.Content.PropertyContextHelpOption == "text");
- }
- [Test]
- public void PreviewBadge()
- {
- Assert.IsTrue(SettingsSection.Content.PreviewBadge == @"In Preview Mode - click to end");
- }
- [Test]
- public void UmbracoLibraryCacheDuration()
- {
- Assert.IsTrue(SettingsSection.Content.UmbracoLibraryCacheDuration == 1800);
- }
- [Test]
- public void ResolveUrlsFromTextString()
- {
- Assert.IsFalse(SettingsSection.Content.ResolveUrlsFromTextString);
- }
- [Test]
- public void MacroErrors()
- {
- Assert.IsTrue(SettingsSection.Content.MacroErrorBehaviour == MacroErrorBehaviour.Inline);
- }
-
- [Test]
- public void DisallowedUploadFiles()
- {
- Assert.IsTrue(SettingsSection.Content.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x)));
- }
-
- [Test]
- public void AllowedUploadFiles()
- {
- Assert.IsTrue(SettingsSection.Content.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x)));
- }
-
- [Test]
- [TestCase("png", true)]
- [TestCase("jpg", true)]
- [TestCase("gif", true)]
- // TODO: Why does it flip to TestingDefaults=true for these two tests on AppVeyor. WHY?
- //[TestCase("bmp", false)]
- //[TestCase("php", false)]
- [TestCase("ashx", false)]
- [TestCase("config", false)]
- public void IsFileAllowedForUpload_WithWhitelist(string extension, bool expected)
- {
- // Make really sure that defaults are NOT used
- TestingDefaults = false;
-
- Debug.WriteLine("Extension being tested", extension);
- Debug.WriteLine("AllowedUploadFiles: {0}", SettingsSection.Content.AllowedUploadFiles);
- Debug.WriteLine("DisallowedUploadFiles: {0}", SettingsSection.Content.DisallowedUploadFiles);
-
- var allowedContainsExtension = SettingsSection.Content.AllowedUploadFiles.Any(x => x.InvariantEquals(extension));
- var disallowedContainsExtension = SettingsSection.Content.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension));
-
- Debug.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension);
- Debug.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension);
-
- Assert.AreEqual(SettingsSection.Content.IsFileAllowedForUpload(extension), expected);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Tests.Configurations.UmbracoSettings
+{
+ [TestFixture]
+ public class ContentElementTests : UmbracoSettingsTests
+ {
+ [Test]
+ public void EmailAddress()
+ {
+ Assert.IsTrue(SettingsSection.Content.NotificationEmailAddress == "robot@umbraco.dk");
+ }
+ [Test]
+ public virtual void DisableHtmlEmail()
+ {
+ Assert.IsTrue(SettingsSection.Content.DisableHtmlEmail == true);
+ }
+
+ [Test]
+ public virtual void Can_Set_Multiple()
+ {
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.Count() == 3);
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).Culture == "default");
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId == 1047);
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId);
+ Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey);
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).Culture == "en-US");
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath == "$site/error [@name = 'error']");
+ Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId);
+ Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey);
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).Culture == "en-UK");
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey == new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"));
+ Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey);
+ Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId);
+ }
+
+ [Test]
+ public void ScriptFolderPath()
+ {
+ Assert.IsTrue(SettingsSection.Content.ScriptFolderPath == "/scripts");
+ }
+ [Test]
+ public void ScriptFileTypes()
+ {
+ Assert.IsTrue(SettingsSection.Content.ScriptFileTypes.All(x => "js,xml".Split(',').Contains(x)));
+ }
+ [Test]
+ public void DisableScriptEditor()
+ {
+ Assert.IsTrue(SettingsSection.Content.ScriptEditorDisable == false);
+ }
+
+ [Test]
+ public void ImageFileTypes()
+ {
+ Assert.IsTrue(SettingsSection.Content.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x)));
+ }
+ [Test]
+ public void AllowedAttributes()
+ {
+ Assert.IsTrue(SettingsSection.Content.ImageTagAllowedAttributes.All(x => "src,alt,border,class,style,align,id,name,onclick,usemap".Split(',').Contains(x)));
+ }
+ [Test]
+ public virtual void ImageAutoFillProperties()
+ {
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.Count() == 2);
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias == "umbracoFile");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias == "umbracoWidth");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias == "umbracoHeight");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias == "umbracoBytes");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias == "umbracoExtension");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).Alias == "umbracoFile2");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias == "umbracoWidth2");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias == "umbracoHeight2");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias == "umbracoBytes2");
+ Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias == "umbracoExtension2");
+ }
+
+ [Test]
+ public void UploadAllowDirectories()
+ {
+ Assert.IsTrue(SettingsSection.Content.UploadAllowDirectories == true);
+ }
+ [Test]
+ public void DefaultDocumentTypeProperty()
+ {
+ Assert.IsTrue(SettingsSection.Content.DefaultDocumentTypeProperty == "Textstring");
+ }
+ [Test]
+ public void GlobalPreviewStorageEnabled()
+ {
+ Assert.IsTrue(SettingsSection.Content.GlobalPreviewStorageEnabled == false);
+ }
+ [Test]
+ public void CloneXmlContent()
+ {
+ Assert.IsTrue(SettingsSection.Content.CloneXmlContent == true);
+ }
+ [Test]
+ public void EnsureUniqueNaming()
+ {
+ Assert.IsTrue(SettingsSection.Content.EnsureUniqueNaming == true);
+ }
+
+
+ [Test]
+ public void ForceSafeAliases()
+ {
+ Assert.IsTrue(SettingsSection.Content.ForceSafeAliases == true);
+ }
+ [Test]
+ public void XmlCacheEnabled()
+ {
+ Assert.IsTrue(SettingsSection.Content.XmlCacheEnabled == true);
+ }
+ [Test]
+ public void ContinouslyUpdateXmlDiskCache()
+ {
+ Assert.IsTrue(SettingsSection.Content.ContinouslyUpdateXmlDiskCache == true);
+ }
+ [Test]
+ public virtual void XmlContentCheckForDiskChanges()
+ {
+ Assert.IsTrue(SettingsSection.Content.XmlContentCheckForDiskChanges == true);
+ }
+ [Test]
+ public void EnableSplashWhileLoading()
+ {
+ Assert.IsTrue(SettingsSection.Content.EnableSplashWhileLoading == false);
+ }
+ [Test]
+ public void PropertyContextHelpOption()
+ {
+ Assert.IsTrue(SettingsSection.Content.PropertyContextHelpOption == "text");
+ }
+ [Test]
+ public void PreviewBadge()
+ {
+ Assert.IsTrue(SettingsSection.Content.PreviewBadge == @"In Preview Mode - click to end");
+ }
+ [Test]
+ public void ResolveUrlsFromTextString()
+ {
+ Assert.IsFalse(SettingsSection.Content.ResolveUrlsFromTextString);
+ }
+ [Test]
+ public void MacroErrors()
+ {
+ Assert.IsTrue(SettingsSection.Content.MacroErrorBehaviour == MacroErrorBehaviour.Inline);
+ }
+
+ [Test]
+ public void DisallowedUploadFiles()
+ {
+ Assert.IsTrue(SettingsSection.Content.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x)));
+ }
+
+ [Test]
+ public void AllowedUploadFiles()
+ {
+ Assert.IsTrue(SettingsSection.Content.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x)));
+ }
+
+ [Test]
+ [TestCase("png", true)]
+ [TestCase("jpg", true)]
+ [TestCase("gif", true)]
+ // TODO: Why does it flip to TestingDefaults=true for these two tests on AppVeyor. WHY?
+ //[TestCase("bmp", false)]
+ //[TestCase("php", false)]
+ [TestCase("ashx", false)]
+ [TestCase("config", false)]
+ public void IsFileAllowedForUpload_WithWhitelist(string extension, bool expected)
+ {
+ // Make really sure that defaults are NOT used
+ TestingDefaults = false;
+
+ Debug.WriteLine("Extension being tested", extension);
+ Debug.WriteLine("AllowedUploadFiles: {0}", SettingsSection.Content.AllowedUploadFiles);
+ Debug.WriteLine("DisallowedUploadFiles: {0}", SettingsSection.Content.DisallowedUploadFiles);
+
+ var allowedContainsExtension = SettingsSection.Content.AllowedUploadFiles.Any(x => x.InvariantEquals(extension));
+ var disallowedContainsExtension = SettingsSection.Content.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension));
+
+ Debug.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension);
+ Debug.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension);
+
+ Assert.AreEqual(SettingsSection.Content.IsFileAllowedForUpload(extension), expected);
+ }
+ }
+}
diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config
index 07eb355d68..9b52c8356e 100644
--- a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config
+++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config
@@ -77,10 +77,6 @@
In Preview Mode - click to end]]>
-
-
- 1800
-
-
- $(NuGetPackageFolders.Split(';')[0])
-
-
-
-
-
-
-
-
-
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {5D3B8245-ADA6-453F-A008-50ED04BFE770}
+ Library
+ Properties
+ Umbraco.Tests
+ Umbraco.Tests
+ v4.7.2
+ 512
+ ..\
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+ latest
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ SqlResources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ResourceFiles.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ ImportResources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ TestFiles.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+ Designer
+ Always
+
+
+ Designer
+ Always
+
+
+ Designer
+ Always
+
+
+ Designer
+ Always
+
+
+
+
+
+ Designer
+
+
+
+ Always
+
+
+
+
+ {31785BC3-256C-4613-B2F5-A1B0BDDED8C1}
+ Umbraco.Core
+
+
+ {651E1350-91B6-44B7-BD60-7207006D7003}
+ Umbraco.Web
+
+
+ {07fbc26b-2927-4a22-8d96-d644c667fecc}
+ Umbraco.Examine
+
+
+
+
+ ResXFileCodeGenerator
+ SqlResources.Designer.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ ImportResources.Designer.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ ResourceFiles.Designer.cs
+
+
+ ResXFileCodeGenerator
+ TestFiles.Designer.cs
+ Designer
+
+
+
+
+ Designer
+ Always
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+ $(NuGetPackageFolders.Split(';')[0])
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config
index 9e4644c20e..59f8e7bd5d 100644
--- a/src/Umbraco.Web.UI/config/umbracoSettings.config
+++ b/src/Umbraco.Web.UI/config/umbracoSettings.config
@@ -78,9 +78,6 @@
In Preview Mode - click to end
]]>
-
-
- 1800
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
index 8f354240e0..db4b03df1e 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
@@ -1,725 +1,741 @@
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Xml.XPath;
-using Examine;
-using Examine.LuceneEngine.SearchCriteria;
-using Examine.Providers;
-using Lucene.Net.Store;
-using Umbraco.Core;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Models;
-using Umbraco.Core.Models.PublishedContent;
-using Umbraco.Core.Xml;
-using Umbraco.Examine;
-using umbraco;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Services;
-using Umbraco.Web.Composing;
-
-namespace Umbraco.Web.PublishedCache.XmlPublishedCache
-{
- ///
- /// An IPublishedMediaStore that first checks for the media in Examine, and then reverts to the database
- ///
- ///
- /// NOTE: In the future if we want to properly cache all media this class can be extended or replaced when these classes/interfaces are exposed publicly.
- ///
- internal class PublishedMediaCache : PublishedCacheBase, IPublishedMediaCache
- {
- private readonly IMediaService _mediaService;
- private readonly IUserService _userService;
-
- // by default these are null unless specified by the ctor dedicated to tests
- // when they are null the cache derives them from the ExamineManager, see
- // method GetExamineManagerSafe().
- //
- private readonly ISearcher _searchProvider;
- private readonly IIndexer _indexProvider;
- private readonly XmlStore _xmlStore;
- private readonly PublishedContentTypeCache _contentTypeCache;
-
- // must be specified by the ctor
- private readonly ICacheProvider _cacheProvider;
-
- public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
- : base(false)
- {
- _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
- _userService = userService ?? throw new ArgumentNullException(nameof(userService));
-
- _cacheProvider = cacheProvider;
- _xmlStore = xmlStore;
- _contentTypeCache = contentTypeCache;
- }
-
- ///
- /// Generally used for unit testing to use an explicit examine searcher
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, BaseIndexProvider indexProvider, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
- : base(false)
- {
- _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
- _userService = userService ?? throw new ArgumentNullException(nameof(userService));
- _searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider));
- _indexProvider = indexProvider ?? throw new ArgumentNullException(nameof(indexProvider));
- _cacheProvider = cacheProvider;
- _contentTypeCache = contentTypeCache;
- }
-
- static PublishedMediaCache()
- {
- InitializeCacheConfig();
- }
-
- public override IPublishedContent GetById(bool preview, int nodeId)
- {
- return GetUmbracoMedia(nodeId);
- }
-
- public override IPublishedContent GetById(bool preview, Guid nodeId)
- {
- throw new NotImplementedException();
- }
-
- public override bool HasById(bool preview, int contentId)
- {
- return GetUmbracoMedia(contentId) != null;
- }
-
- public override IEnumerable GetAtRoot(bool preview)
- {
- var searchProvider = GetSearchProviderSafe();
-
- if (searchProvider != null)
- {
- try
- {
- // first check in Examine for the cache values
- // +(+parentID:-1) +__IndexType:media
-
- var criteria = searchProvider.CreateCriteria("media");
- var filter = criteria.ParentId(-1).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
-
- var result = searchProvider.Search(filter.Compile());
- if (result != null)
- return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x)));
- }
- catch (Exception ex)
- {
- if (ex is FileNotFoundException)
- {
- //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
- //See this thread: http://examine.cdodeplex.com/discussions/264341
- //Catch the exception here for the time being, and just fallback to GetMedia
- //TODO: Need to fix examine in LB scenarios!
- Current.Logger.Error("Could not load data from Examine index for media", ex);
- }
- else if (ex is AlreadyClosedException)
- {
- //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
- //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
- Current.Logger.Error("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
- }
- else throw;
- }
- }
-
- //something went wrong, fetch from the db
-
- var rootMedia = _mediaService.GetRootMedia();
- return rootMedia.Select(m => GetUmbracoMedia(m.Id));
- }
-
- public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //var navigator = CreateNavigator(preview);
- //var iterator = navigator.Select(xpath, vars);
- //return GetSingleByXPath(iterator);
- }
-
- public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //var navigator = CreateNavigator(preview);
- //var iterator = navigator.Select(xpath, vars);
- //return GetSingleByXPath(iterator);
- }
-
- private IPublishedContent GetSingleByXPath(XPathNodeIterator iterator)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //if (iterator.MoveNext() == false) return null;
- //var idAttr = iterator.Current.GetAttribute("id", "");
- //int id;
- //return int.TryParse(idAttr, out id) ? GetUmbracoMedia(id) : null;
- }
-
- public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //var navigator = CreateNavigator(preview);
- //var iterator = navigator.Select(xpath, vars);
- //return GetByXPath(iterator);
- }
-
- public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //var navigator = CreateNavigator(preview);
- //var iterator = navigator.Select(xpath, vars);
- //return GetByXPath(iterator);
- }
-
- private IEnumerable GetByXPath(XPathNodeIterator iterator)
- {
- while (iterator.MoveNext())
- {
- var idAttr = iterator.Current.GetAttribute("id", "");
- int id;
- if (int.TryParse(idAttr, out id))
- yield return GetUmbracoMedia(id);
- }
- }
-
- public override XPathNavigator CreateNavigator(bool preview)
- {
- throw new NotImplementedException("PublishedMediaCache does not support XPath.");
- //var doc = _xmlStore.GetMediaXml();
- //return doc.CreateNavigator();
- }
-
- public override XPathNavigator CreateNodeNavigator(int id, bool preview)
- {
- // preview is ignored for media cache
-
- // this code is mostly used when replacing old media.ToXml() code, and that code
- // stored the XML attached to the media itself - so for some time in memory - so
- // unless we implement some sort of cache here, we're probably degrading perfs.
-
- XPathNavigator navigator = null;
- var node = _xmlStore.GetMediaXmlNode(id);
- if (node != null)
- {
- navigator = node.CreateNavigator();
- }
- return navigator;
- }
-
- public override bool HasContent(bool preview) { throw new NotImplementedException(); }
-
- private static IExamineManager GetExamineManagerSafe()
- {
- try
- {
- return ExamineManager.Instance;
- }
- catch (TypeInitializationException)
- {
- return null;
- }
- }
-
- private ISearcher GetSearchProviderSafe()
- {
- if (_searchProvider != null)
- return _searchProvider;
-
- var eMgr = GetExamineManagerSafe();
- if (eMgr == null) return null;
-
- try
- {
- //by default use the internal index
- return eMgr.GetSearcher(Constants.Examine.InternalIndexer);
- }
- catch (FileNotFoundException)
- {
- //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
- //See this thread: http://examine.cdodeplex.com/discussions/264341
- //Catch the exception here for the time being, and just fallback to GetMedia
- //TODO: Need to fix examine in LB scenarios!
- }
- catch (NullReferenceException)
- {
- //This will occur when the search provider cannot be initialized. In newer examine versions the initialization is lazy and therefore
- // the manager will return the singleton without throwing initialization errors, however if examine isn't configured correctly a null
- // reference error will occur because the examine settings are null.
- }
- catch (AlreadyClosedException)
- {
- //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
- //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
- }
- return null;
- }
-
- private IPublishedContent GetUmbracoMedia(int id)
- {
- // this recreates an IPublishedContent and model each time
- // it is called, but at least it should NOT hit the database
- // nor Lucene each time, relying on the memory cache instead
-
- if (id <= 0) return null; // fail fast
-
- var cacheValues = GetCacheValues(id, GetUmbracoMediaCacheValues);
-
- return cacheValues == null ? null : CreateFromCacheValues(cacheValues);
- }
-
- private CacheValues GetUmbracoMediaCacheValues(int id)
- {
- var searchProvider = GetSearchProviderSafe();
-
- if (searchProvider != null)
- {
- try
- {
- // first check in Examine as this is WAY faster
- //
- // the filter will create a query like this:
- // +(+__NodeId:3113 -__Path:-1,-21,*) +__IndexType:media
- //
- // note that since the use of the wildcard, it automatically escapes it in Lucene.
-
- var criteria = searchProvider.CreateCriteria("media");
- var filter = criteria.Id(id.ToInvariantString()).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
-
- var result = searchProvider.Search(filter.Compile()).FirstOrDefault();
- if (result != null) return ConvertFromSearchResult(result);
- }
- catch (Exception ex)
- {
- if (ex is FileNotFoundException)
- {
- //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
- //See this thread: http://examine.cdodeplex.com/discussions/264341
- //Catch the exception here for the time being, and just fallback to GetMedia
- //TODO: Need to fix examine in LB scenarios!
- Current.Logger.Error("Could not load data from Examine index for media", ex);
- }
- else if (ex is AlreadyClosedException)
- {
- //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
- //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
- Current.Logger.Error("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
- }
- else throw;
- }
- }
-
- // don't log a warning here, as it can flood the log in case of eg a media picker referencing a media
- // that has been deleted, hence is not in the Examine index anymore (for a good reason). try to get
- // the media from the service, first
- var media = _mediaService.GetById(id);
- if (media == null || media.Trashed) return null; // not found, ok
-
- // so, the media was not found in Examine's index *yet* it exists, which probably indicates that
- // the index is corrupted. Or not up-to-date. Log a warning, but only once, and only if seeing the
- // error more that a number of times.
-
- var miss = Interlocked.CompareExchange(ref _examineIndexMiss, 0, 0); // volatile read
- if (miss < ExamineIndexMissMax && Interlocked.Increment(ref _examineIndexMiss) == ExamineIndexMissMax)
- Current.Logger.Warn(() => $"Failed ({ExamineIndexMissMax} times) to retrieve medias from Examine index and had to load"
- + " them from DB. This may indicate that the Examine index is corrupted.");
-
- return ConvertFromIMedia(media);
- }
-
- private const int ExamineIndexMissMax = 10;
- private int _examineIndexMiss;
-
- internal CacheValues ConvertFromXPathNodeIterator(XPathNodeIterator media, int id)
- {
- if (media?.Current != null)
- {
- return media.Current.Name.InvariantEquals("error")
- ? null
- : ConvertFromXPathNavigator(media.Current);
- }
-
- Current.Logger.Warn(() =>
- $"Could not retrieve media {id} from Examine index or from legacy library.GetMedia method");
-
- return null;
- }
-
- internal CacheValues ConvertFromSearchResult(SearchResult searchResult)
- {
- // note: fixing fields in 7.x, removed by Shan for 8.0
-
- return new CacheValues
- {
- Values = searchResult.Fields,
- FromExamine = true
- };
- }
-
- internal CacheValues ConvertFromXPathNavigator(XPathNavigator xpath, bool forceNav = false)
- {
- if (xpath == null) throw new ArgumentNullException(nameof(xpath));
-
- var values = new Dictionary { { "nodeName", xpath.GetAttribute("nodeName", "") } };
- values["nodeTypeAlias"] = xpath.Name;
-
- var result = xpath.SelectChildren(XPathNodeType.Element);
- //add the attributes e.g. id, parentId etc
- if (result.Current != null && result.Current.HasAttributes)
- {
- if (result.Current.MoveToFirstAttribute())
- {
- //checking for duplicate keys because of the 'nodeTypeAlias' might already be added above.
- if (values.ContainsKey(result.Current.Name) == false)
- {
- values[result.Current.Name] = result.Current.Value;
- }
- while (result.Current.MoveToNextAttribute())
- {
- if (values.ContainsKey(result.Current.Name) == false)
- {
- values[result.Current.Name] = result.Current.Value;
- }
- }
- result.Current.MoveToParent();
- }
- }
- // because, migration
- if (values.ContainsKey("key") == false)
- values["key"] = Guid.Empty.ToString();
- //add the user props
- while (result.MoveNext())
- {
- if (result.Current != null && result.Current.HasAttributes == false)
- {
- var value = result.Current.Value;
- if (string.IsNullOrEmpty(value))
- {
- if (result.Current.HasAttributes || result.Current.SelectChildren(XPathNodeType.Element).Count > 0)
- {
- value = result.Current.OuterXml;
- }
- }
- values[result.Current.Name] = value;
- }
- }
-
- return new CacheValues
- {
- Values = values,
- XPath = forceNav ? xpath : null // outside of tests we do NOT want to cache the navigator!
- };
- }
-
- internal CacheValues ConvertFromIMedia(IMedia media)
- {
- var values = new Dictionary();
-
- var creator = _userService.GetProfileById(media.CreatorId);
- var creatorName = creator == null ? "" : creator.Name;
-
- values["id"] = media.Id.ToString();
- values["key"] = media.Key.ToString();
- values["parentID"] = media.ParentId.ToString();
- values["level"] = media.Level.ToString();
- values["creatorID"] = media.CreatorId.ToString();
- values["creatorName"] = creatorName;
- values["writerID"] = media.CreatorId.ToString();
- values["writerName"] = creatorName;
- values["template"] = "0";
- values["urlName"] = "";
- values["sortOrder"] = media.SortOrder.ToString();
- values["createDate"] = media.CreateDate.ToString("yyyy-MM-dd HH:mm:ss");
- values["updateDate"] = media.UpdateDate.ToString("yyyy-MM-dd HH:mm:ss");
- values["nodeName"] = media.Name;
- values["path"] = media.Path;
- values["nodeType"] = media.ContentType.Id.ToString();
- values["nodeTypeAlias"] = media.ContentType.Alias;
-
- // add the user props
- foreach (var prop in media.Properties)
- values[prop.Alias] = prop.GetValue()?.ToString();
-
- return new CacheValues
- {
- Values = values
- };
- }
-
- ///
- /// We will need to first check if the document was loaded by Examine, if so we'll need to check if this property exists
- /// in the results, if it does not, then we'll have to revert to looking up in the db.
- ///
- ///
- ///
- ///
- private IPublishedProperty GetProperty(DictionaryPublishedContent dd, string alias)
- {
- //lets check if the alias does not exist on the document.
- //NOTE: Examine will not index empty values and we do not output empty XML Elements to the cache - either of these situations
- // would mean that the property is missing from the collection whether we are getting the value from Examine or from the library media cache.
- if (dd.Properties.All(x => x.Alias.InvariantEquals(alias) == false))
- {
- return null;
- }
-
- if (dd.LoadedFromExamine)
- {
- //We are going to check for a special field however, that is because in some cases we store a 'Raw'
- //value in the index such as for xml/html.
- var rawValue = dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(UmbracoExamineIndexer.RawFieldPrefix + alias));
- return rawValue
- ?? dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
- }
-
- //if its not loaded from examine, then just return the property
- return dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
- }
-
- ///
- /// A Helper methods to return the children for media whther it is based on examine or xml
- ///
- ///
- ///
- ///
- private IEnumerable GetChildrenMedia(int parentId, XPathNavigator xpath = null)
- {
-
- //if there is no navigator, try examine first, then re-look it up
- if (xpath == null)
- {
- var searchProvider = GetSearchProviderSafe();
-
- if (searchProvider != null)
- {
- try
- {
- //first check in Examine as this is WAY faster
- var criteria = searchProvider.CreateCriteria("media");
-
- var filter = criteria.ParentId(parentId).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
- //the above filter will create a query like this, NOTE: That since the use of the wildcard, it automatically escapes it in Lucene.
- //+(+parentId:3113 -__Path:-1,-21,*) +__IndexType:media
-
- // sort with the Sort field (updated for 8.0)
- var results = searchProvider.Search(
- filter.And().OrderBy(new SortableField("sortOrder", SortType.Int)).Compile());
-
- if (results.Any())
- {
- // var medias = results.Select(ConvertFromSearchResult);
- var medias = results.Select(x =>
- {
- int nid;
- if (int.TryParse(x["__NodeId"], out nid) == false && int.TryParse(x["NodeId"], out nid) == false)
- throw new Exception("Failed to extract NodeId from search result.");
- var cacheValues = GetCacheValues(nid, id => ConvertFromSearchResult(x));
- return CreateFromCacheValues(cacheValues);
- });
-
- return medias;
- }
-
- //if there's no result then return null. Previously we defaulted back to library.GetMedia below
- //but this will always get called for when we are getting descendents since many items won't have
- //children and then we are hitting the database again!
- //So instead we're going to rely on Examine to have the correct results like it should.
- return Enumerable.Empty();
- }
- catch (FileNotFoundException)
- {
- //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
- //See this thread: http://examine.cdodeplex.com/discussions/264341
- //Catch the exception here for the time being, and just fallback to GetMedia
- }
- }
-
- //falling back to get media
-
- var media = library.GetMedia(parentId, true);
- if (media?.Current != null)
- {
- xpath = media.Current;
- }
- else
- {
- return Enumerable.Empty();
- }
- }
-
- var mediaList = new List();
-
- // this is so bad, really
- var item = xpath.Select("//*[@id='" + parentId + "']");
- if (item.Current == null)
- return Enumerable.Empty();
- var items = item.Current.SelectChildren(XPathNodeType.Element);
-
- // and this does not work, because... meh
- //var q = "//* [@id='" + parentId + "']/* [@id]";
- //var items = xpath.Select(q);
-
- foreach (XPathNavigator itemm in items)
- {
- int id;
- if (int.TryParse(itemm.GetAttribute("id", ""), out id) == false)
- continue; // wtf?
- var captured = itemm;
- var cacheValues = GetCacheValues(id, idd => ConvertFromXPathNavigator(captured));
- mediaList.Add(CreateFromCacheValues(cacheValues));
- }
-
- ////The xpath might be the whole xpath including the current ones ancestors so we need to select the current node
- //var item = xpath.Select("//*[@id='" + parentId + "']");
- //if (item.Current == null)
- //{
- // return Enumerable.Empty();
- //}
- //var children = item.Current.SelectChildren(XPathNodeType.Element);
-
- //foreach(XPathNavigator x in children)
- //{
- // //NOTE: I'm not sure why this is here, it is from legacy code of ExamineBackedMedia, but
- // // will leave it here as it must have done something!
- // if (x.Name != "contents")
- // {
- // //make sure it's actually a node, not a property
- // if (!string.IsNullOrEmpty(x.GetAttribute("path", "")) &&
- // !string.IsNullOrEmpty(x.GetAttribute("id", "")))
- // {
- // mediaList.Add(ConvertFromXPathNavigator(x));
- // }
- // }
- //}
-
- return mediaList;
- }
-
- internal void Resync()
- {
- // clear recursive properties cached by XmlPublishedContent.GetProperty
- // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch)
- // NOTE all properties cleared when clearing the content cache (see content cache)
- //_cacheProvider.ClearCacheObjectTypes();
- //_cacheProvider.ClearCacheByKeySearch("XmlPublishedCache.PublishedMediaCache:RecursiveProperty-");
- }
-
- #region Content types
-
- public override PublishedContentType GetContentType(int id)
- {
- return _contentTypeCache.Get(PublishedItemType.Media, id);
- }
-
- public override PublishedContentType GetContentType(string alias)
- {
- return _contentTypeCache.Get(PublishedItemType.Media, alias);
- }
-
- public override IEnumerable GetByContentType(PublishedContentType contentType)
- {
- throw new NotImplementedException();
- }
-
- #endregion
-
- // REFACTORING
-
- // caching the basic atomic values - and the parent id
- // but NOT caching actual parent nor children and NOT even
- // the list of children ids - BUT caching the path
-
- internal class CacheValues
- {
- public IReadOnlyDictionary Values { get; set; }
- public XPathNavigator XPath { get; set; }
- public bool FromExamine { get; set; }
- }
-
- public const string PublishedMediaCacheKey = "MediaCacheMeh.";
- private const int PublishedMediaCacheTimespanSeconds = 4 * 60; // 4 mins
- private static TimeSpan _publishedMediaCacheTimespan;
- private static bool _publishedMediaCacheEnabled;
-
- private static void InitializeCacheConfig()
- {
- var value = ConfigurationManager.AppSettings["Umbraco.PublishedMediaCache.Seconds"];
- int seconds;
- if (int.TryParse(value, out seconds) == false)
- seconds = PublishedMediaCacheTimespanSeconds;
- if (seconds > 0)
- {
- _publishedMediaCacheEnabled = true;
- _publishedMediaCacheTimespan = TimeSpan.FromSeconds(seconds);
- }
- else
- {
- _publishedMediaCacheEnabled = false;
- }
- }
-
- internal IPublishedContent CreateFromCacheValues(CacheValues cacheValues)
- {
- var content = new DictionaryPublishedContent(
- cacheValues.Values,
- parentId => parentId < 0 ? null : GetUmbracoMedia(parentId),
- GetChildrenMedia,
- GetProperty,
- _cacheProvider,
- _contentTypeCache,
- cacheValues.XPath, // though, outside of tests, that should be null
- cacheValues.FromExamine
- );
- return content.CreateModel();
- }
-
- private static CacheValues GetCacheValues(int id, Func func)
- {
- if (_publishedMediaCacheEnabled == false)
- return func(id);
-
- var cache = Current.ApplicationCache.RuntimeCache;
- var key = PublishedMediaCacheKey + id;
- return (CacheValues)cache.GetCacheItem(key, () => func(id), _publishedMediaCacheTimespan);
- }
-
- internal static void ClearCache(int id)
- {
- var cache = Current.ApplicationCache.RuntimeCache;
- var sid = id.ToString();
- var key = PublishedMediaCacheKey + sid;
-
- // we do clear a lot of things... but the cache refresher is somewhat
- // convoluted and it's hard to tell what to clear exactly ;-(
-
- // clear the parent - NOT (why?)
- //var exist = (CacheValues) cache.GetCacheItem(key);
- //if (exist != null)
- // cache.ClearCacheItem(PublishedMediaCacheKey + GetValuesValue(exist.Values, "parentID"));
-
- // clear the item
- cache.ClearCacheItem(key);
-
- // clear all children - in case we moved and their path has changed
- var fid = "/" + sid + "/";
- cache.ClearCacheObjectTypes((k, v) =>
- GetValuesValue(v.Values, "path", "__Path").Contains(fid));
- }
-
- private static string GetValuesValue(IReadOnlyDictionary d, params string[] keys)
- {
- string value = null;
- var ignored = keys.Any(x => d.TryGetValue(x, out value));
- return value ?? "";
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Xml.XPath;
+using Examine;
+using Examine.LuceneEngine.SearchCriteria;
+using Examine.Providers;
+using Lucene.Net.Store;
+using Umbraco.Core;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Core.Xml;
+using Umbraco.Examine;
+using umbraco;
+using Umbraco.Core.Cache;
+using Umbraco.Core.Services;
+using Umbraco.Web.Composing;
+
+namespace Umbraco.Web.PublishedCache.XmlPublishedCache
+{
+ ///
+ /// An IPublishedMediaStore that first checks for the media in Examine, and then reverts to the database
+ ///
+ ///
+ /// NOTE: In the future if we want to properly cache all media this class can be extended or replaced when these classes/interfaces are exposed publicly.
+ ///
+ internal class PublishedMediaCache : PublishedCacheBase, IPublishedMediaCache
+ {
+ private readonly IMediaService _mediaService;
+ private readonly IUserService _userService;
+
+ // by default these are null unless specified by the ctor dedicated to tests
+ // when they are null the cache derives them from the ExamineManager, see
+ // method GetExamineManagerSafe().
+ //
+ private readonly ISearcher _searchProvider;
+ private readonly IIndexer _indexProvider;
+ private readonly XmlStore _xmlStore;
+ private readonly PublishedContentTypeCache _contentTypeCache;
+
+ // must be specified by the ctor
+ private readonly ICacheProvider _cacheProvider;
+
+ public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
+ : base(false)
+ {
+ _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
+ _userService = userService ?? throw new ArgumentNullException(nameof(userService));
+
+ _cacheProvider = cacheProvider;
+ _xmlStore = xmlStore;
+ _contentTypeCache = contentTypeCache;
+ }
+
+ ///
+ /// Generally used for unit testing to use an explicit examine searcher
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, BaseIndexProvider indexProvider, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
+ : base(false)
+ {
+ _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
+ _userService = userService ?? throw new ArgumentNullException(nameof(userService));
+ _searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider));
+ _indexProvider = indexProvider ?? throw new ArgumentNullException(nameof(indexProvider));
+ _cacheProvider = cacheProvider;
+ _contentTypeCache = contentTypeCache;
+ }
+
+ static PublishedMediaCache()
+ {
+ InitializeCacheConfig();
+ }
+
+ public override IPublishedContent GetById(bool preview, int nodeId)
+ {
+ return GetUmbracoMedia(nodeId);
+ }
+
+ public override IPublishedContent GetById(bool preview, Guid nodeId)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool HasById(bool preview, int contentId)
+ {
+ return GetUmbracoMedia(contentId) != null;
+ }
+
+ public override IEnumerable GetAtRoot(bool preview)
+ {
+ var searchProvider = GetSearchProviderSafe();
+
+ if (searchProvider != null)
+ {
+ try
+ {
+ // first check in Examine for the cache values
+ // +(+parentID:-1) +__IndexType:media
+
+ var criteria = searchProvider.CreateCriteria("media");
+ var filter = criteria.ParentId(-1).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
+
+ var result = searchProvider.Search(filter.Compile());
+ if (result != null)
+ return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x)));
+ }
+ catch (Exception ex)
+ {
+ if (ex is FileNotFoundException)
+ {
+ //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
+ //See this thread: http://examine.cdodeplex.com/discussions/264341
+ //Catch the exception here for the time being, and just fallback to GetMedia
+ //TODO: Need to fix examine in LB scenarios!
+ Current.Logger.Error("Could not load data from Examine index for media", ex);
+ }
+ else if (ex is AlreadyClosedException)
+ {
+ //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
+ //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
+ Current.Logger.Error("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
+ }
+ else throw;
+ }
+ }
+
+ //something went wrong, fetch from the db
+
+ var rootMedia = _mediaService.GetRootMedia();
+ return rootMedia.Select(m => GetUmbracoMedia(m.Id));
+ }
+
+ public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //var navigator = CreateNavigator(preview);
+ //var iterator = navigator.Select(xpath, vars);
+ //return GetSingleByXPath(iterator);
+ }
+
+ public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //var navigator = CreateNavigator(preview);
+ //var iterator = navigator.Select(xpath, vars);
+ //return GetSingleByXPath(iterator);
+ }
+
+ private IPublishedContent GetSingleByXPath(XPathNodeIterator iterator)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //if (iterator.MoveNext() == false) return null;
+ //var idAttr = iterator.Current.GetAttribute("id", "");
+ //int id;
+ //return int.TryParse(idAttr, out id) ? GetUmbracoMedia(id) : null;
+ }
+
+ public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //var navigator = CreateNavigator(preview);
+ //var iterator = navigator.Select(xpath, vars);
+ //return GetByXPath(iterator);
+ }
+
+ public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //var navigator = CreateNavigator(preview);
+ //var iterator = navigator.Select(xpath, vars);
+ //return GetByXPath(iterator);
+ }
+
+ private IEnumerable GetByXPath(XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext())
+ {
+ var idAttr = iterator.Current.GetAttribute("id", "");
+ int id;
+ if (int.TryParse(idAttr, out id))
+ yield return GetUmbracoMedia(id);
+ }
+ }
+
+ public override XPathNavigator CreateNavigator(bool preview)
+ {
+ throw new NotImplementedException("PublishedMediaCache does not support XPath.");
+ //var doc = _xmlStore.GetMediaXml();
+ //return doc.CreateNavigator();
+ }
+
+ public override XPathNavigator CreateNodeNavigator(int id, bool preview)
+ {
+ // preview is ignored for media cache
+
+ // this code is mostly used when replacing old media.ToXml() code, and that code
+ // stored the XML attached to the media itself - so for some time in memory - so
+ // unless we implement some sort of cache here, we're probably degrading perfs.
+
+ XPathNavigator navigator = null;
+ var node = _xmlStore.GetMediaXmlNode(id);
+ if (node != null)
+ {
+ navigator = node.CreateNavigator();
+ }
+ return navigator;
+ }
+
+ public override bool HasContent(bool preview) { throw new NotImplementedException(); }
+
+ private static IExamineManager GetExamineManagerSafe()
+ {
+ try
+ {
+ return ExamineManager.Instance;
+ }
+ catch (TypeInitializationException)
+ {
+ return null;
+ }
+ }
+
+ private ISearcher GetSearchProviderSafe()
+ {
+ if (_searchProvider != null)
+ return _searchProvider;
+
+ var eMgr = GetExamineManagerSafe();
+ if (eMgr == null) return null;
+
+ try
+ {
+ //by default use the internal index
+ return eMgr.GetSearcher(Constants.Examine.InternalIndexer);
+ }
+ catch (FileNotFoundException)
+ {
+ //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
+ //See this thread: http://examine.cdodeplex.com/discussions/264341
+ //Catch the exception here for the time being, and just fallback to GetMedia
+ //TODO: Need to fix examine in LB scenarios!
+ }
+ catch (NullReferenceException)
+ {
+ //This will occur when the search provider cannot be initialized. In newer examine versions the initialization is lazy and therefore
+ // the manager will return the singleton without throwing initialization errors, however if examine isn't configured correctly a null
+ // reference error will occur because the examine settings are null.
+ }
+ catch (AlreadyClosedException)
+ {
+ //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
+ //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
+ }
+ return null;
+ }
+
+ private IPublishedContent GetUmbracoMedia(int id)
+ {
+ // this recreates an IPublishedContent and model each time
+ // it is called, but at least it should NOT hit the database
+ // nor Lucene each time, relying on the memory cache instead
+
+ if (id <= 0) return null; // fail fast
+
+ var cacheValues = GetCacheValues(id, GetUmbracoMediaCacheValues);
+
+ return cacheValues == null ? null : CreateFromCacheValues(cacheValues);
+ }
+
+ private CacheValues GetUmbracoMediaCacheValues(int id)
+ {
+ var searchProvider = GetSearchProviderSafe();
+
+ if (searchProvider != null)
+ {
+ try
+ {
+ // first check in Examine as this is WAY faster
+ //
+ // the filter will create a query like this:
+ // +(+__NodeId:3113 -__Path:-1,-21,*) +__IndexType:media
+ //
+ // note that since the use of the wildcard, it automatically escapes it in Lucene.
+
+ var criteria = searchProvider.CreateCriteria("media");
+ var filter = criteria.Id(id.ToInvariantString()).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
+
+ var result = searchProvider.Search(filter.Compile()).FirstOrDefault();
+ if (result != null) return ConvertFromSearchResult(result);
+ }
+ catch (Exception ex)
+ {
+ if (ex is FileNotFoundException)
+ {
+ //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
+ //See this thread: http://examine.cdodeplex.com/discussions/264341
+ //Catch the exception here for the time being, and just fallback to GetMedia
+ //TODO: Need to fix examine in LB scenarios!
+ Current.Logger.Error("Could not load data from Examine index for media", ex);
+ }
+ else if (ex is AlreadyClosedException)
+ {
+ //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
+ //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
+ Current.Logger.Error("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
+ }
+ else throw;
+ }
+ }
+
+ // don't log a warning here, as it can flood the log in case of eg a media picker referencing a media
+ // that has been deleted, hence is not in the Examine index anymore (for a good reason). try to get
+ // the media from the service, first
+ var media = _mediaService.GetById(id);
+ if (media == null || media.Trashed) return null; // not found, ok
+
+ // so, the media was not found in Examine's index *yet* it exists, which probably indicates that
+ // the index is corrupted. Or not up-to-date. Log a warning, but only once, and only if seeing the
+ // error more that a number of times.
+
+ var miss = Interlocked.CompareExchange(ref _examineIndexMiss, 0, 0); // volatile read
+ if (miss < ExamineIndexMissMax && Interlocked.Increment(ref _examineIndexMiss) == ExamineIndexMissMax)
+ Current.Logger.Warn(() => $"Failed ({ExamineIndexMissMax} times) to retrieve medias from Examine index and had to load"
+ + " them from DB. This may indicate that the Examine index is corrupted.");
+
+ return ConvertFromIMedia(media);
+ }
+
+ private const int ExamineIndexMissMax = 10;
+ private int _examineIndexMiss;
+
+ internal CacheValues ConvertFromXPathNodeIterator(XPathNodeIterator media, int id)
+ {
+ if (media?.Current != null)
+ {
+ return media.Current.Name.InvariantEquals("error")
+ ? null
+ : ConvertFromXPathNavigator(media.Current);
+ }
+
+ Current.Logger.Warn(() =>
+ $"Could not retrieve media {id} from Examine index or from legacy library.GetMedia method");
+
+ return null;
+ }
+
+ internal CacheValues ConvertFromSearchResult(SearchResult searchResult)
+ {
+ // note: fixing fields in 7.x, removed by Shan for 8.0
+
+ return new CacheValues
+ {
+ Values = searchResult.Fields,
+ FromExamine = true
+ };
+ }
+
+ internal CacheValues ConvertFromXPathNavigator(XPathNavigator xpath, bool forceNav = false)
+ {
+ if (xpath == null) throw new ArgumentNullException(nameof(xpath));
+
+ var values = new Dictionary { { "nodeName", xpath.GetAttribute("nodeName", "") } };
+ values["nodeTypeAlias"] = xpath.Name;
+
+ var result = xpath.SelectChildren(XPathNodeType.Element);
+ //add the attributes e.g. id, parentId etc
+ if (result.Current != null && result.Current.HasAttributes)
+ {
+ if (result.Current.MoveToFirstAttribute())
+ {
+ //checking for duplicate keys because of the 'nodeTypeAlias' might already be added above.
+ if (values.ContainsKey(result.Current.Name) == false)
+ {
+ values[result.Current.Name] = result.Current.Value;
+ }
+ while (result.Current.MoveToNextAttribute())
+ {
+ if (values.ContainsKey(result.Current.Name) == false)
+ {
+ values[result.Current.Name] = result.Current.Value;
+ }
+ }
+ result.Current.MoveToParent();
+ }
+ }
+ // because, migration
+ if (values.ContainsKey("key") == false)
+ values["key"] = Guid.Empty.ToString();
+ //add the user props
+ while (result.MoveNext())
+ {
+ if (result.Current != null && result.Current.HasAttributes == false)
+ {
+ var value = result.Current.Value;
+ if (string.IsNullOrEmpty(value))
+ {
+ if (result.Current.HasAttributes || result.Current.SelectChildren(XPathNodeType.Element).Count > 0)
+ {
+ value = result.Current.OuterXml;
+ }
+ }
+ values[result.Current.Name] = value;
+ }
+ }
+
+ return new CacheValues
+ {
+ Values = values,
+ XPath = forceNav ? xpath : null // outside of tests we do NOT want to cache the navigator!
+ };
+ }
+
+ internal CacheValues ConvertFromIMedia(IMedia media)
+ {
+ var values = new Dictionary();
+
+ var creator = _userService.GetProfileById(media.CreatorId);
+ var creatorName = creator == null ? "" : creator.Name;
+
+ values["id"] = media.Id.ToString();
+ values["key"] = media.Key.ToString();
+ values["parentID"] = media.ParentId.ToString();
+ values["level"] = media.Level.ToString();
+ values["creatorID"] = media.CreatorId.ToString();
+ values["creatorName"] = creatorName;
+ values["writerID"] = media.CreatorId.ToString();
+ values["writerName"] = creatorName;
+ values["template"] = "0";
+ values["urlName"] = "";
+ values["sortOrder"] = media.SortOrder.ToString();
+ values["createDate"] = media.CreateDate.ToString("yyyy-MM-dd HH:mm:ss");
+ values["updateDate"] = media.UpdateDate.ToString("yyyy-MM-dd HH:mm:ss");
+ values["nodeName"] = media.Name;
+ values["path"] = media.Path;
+ values["nodeType"] = media.ContentType.Id.ToString();
+ values["nodeTypeAlias"] = media.ContentType.Alias;
+
+ // add the user props
+ foreach (var prop in media.Properties)
+ values[prop.Alias] = prop.GetValue()?.ToString();
+
+ return new CacheValues
+ {
+ Values = values
+ };
+ }
+
+ ///
+ /// We will need to first check if the document was loaded by Examine, if so we'll need to check if this property exists
+ /// in the results, if it does not, then we'll have to revert to looking up in the db.
+ ///
+ ///
+ ///
+ ///
+ private IPublishedProperty GetProperty(DictionaryPublishedContent dd, string alias)
+ {
+ //lets check if the alias does not exist on the document.
+ //NOTE: Examine will not index empty values and we do not output empty XML Elements to the cache - either of these situations
+ // would mean that the property is missing from the collection whether we are getting the value from Examine or from the library media cache.
+ if (dd.Properties.All(x => x.Alias.InvariantEquals(alias) == false))
+ {
+ return null;
+ }
+
+ if (dd.LoadedFromExamine)
+ {
+ //We are going to check for a special field however, that is because in some cases we store a 'Raw'
+ //value in the index such as for xml/html.
+ var rawValue = dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(UmbracoExamineIndexer.RawFieldPrefix + alias));
+ return rawValue
+ ?? dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
+ }
+
+ //if its not loaded from examine, then just return the property
+ return dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
+ }
+
+ ///
+ /// A Helper methods to return the children for media whther it is based on examine or xml
+ ///
+ ///
+ ///
+ ///
+ private IEnumerable GetChildrenMedia(int parentId, XPathNavigator xpath = null)
+ {
+ //if there is no navigator, try examine first, then re-look it up
+ if (xpath != null)
+ {
+ return ToIPublishedContent(parentId, xpath);
+ }
+
+ var searchProvider = GetSearchProviderSafe();
+
+ if (searchProvider != null)
+ {
+ try
+ {
+ //first check in Examine as this is WAY faster
+ var criteria = searchProvider.CreateCriteria("media");
+
+ var filter = criteria.ParentId(parentId).Not().Field(UmbracoExamineIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
+ //the above filter will create a query like this, NOTE: That since the use of the wildcard, it automatically escapes it in Lucene.
+ //+(+parentId:3113 -__Path:-1,-21,*) +__IndexType:media
+
+ // sort with the Sort field (updated for 8.0)
+ var results = searchProvider.Search(
+ filter.And().OrderBy(new SortableField("sortOrder", SortType.Int)).Compile());
+
+ if (results.Any())
+ {
+ // var medias = results.Select(ConvertFromSearchResult);
+ var medias = results.Select(x =>
+ {
+ int nid;
+ if (int.TryParse(x["__NodeId"], out nid) == false && int.TryParse(x["NodeId"], out nid) == false)
+ throw new Exception("Failed to extract NodeId from search result.");
+ var cacheValues = GetCacheValues(nid, id => ConvertFromSearchResult(x));
+ return CreateFromCacheValues(cacheValues);
+ });
+
+ return medias;
+ }
+
+ //if there's no result then return null. Previously we defaulted back to library.GetMedia below
+ //but this will always get called for when we are getting descendents since many items won't have
+ //children and then we are hitting the database again!
+ //So instead we're going to rely on Examine to have the correct results like it should.
+ return Enumerable.Empty();
+ }
+ catch (FileNotFoundException)
+ {
+ //Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
+ //See this thread: http://examine.cdodeplex.com/discussions/264341
+ //Catch the exception here for the time being, and just fallback to GetMedia
+ }
+ }
+
+ //falling back to get media
+ var media = Current.Services.MediaService.GetById(parentId);
+ if (media == null)
+ {
+ return Enumerable.Empty();
+ }
+
+ var serialized = EntityXmlSerializer.Serialize(
+ Current.Services.MediaService,
+ Current.Services.DataTypeService,
+ Current.Services.UserService,
+ Current.Services.LocalizationService,
+ Current.UrlSegmentProviders,
+ media,
+ true);
+
+ var mediaIterator = serialized.CreateNavigator().Select("/");
+
+ if (mediaIterator.Current == null)
+ {
+ return Enumerable.Empty();
+ }
+ xpath = mediaIterator.Current;
+
+ return ToIPublishedContent(parentId, xpath);
+ }
+
+
+ internal IEnumerable ToIPublishedContent(int parentId, XPathNavigator xpath)
+ {
+ var mediaList = new List();
+
+ // this is so bad, really
+ var item = xpath.Select("//*[@id='" + parentId + "']");
+ if (item.Current == null)
+ return Enumerable.Empty();
+ var items = item.Current.SelectChildren(XPathNodeType.Element);
+
+ // and this does not work, because... meh
+ //var q = "//* [@id='" + parentId + "']/* [@id]";
+ //var items = xpath.Select(q);
+
+ foreach (XPathNavigator itemm in items)
+ {
+ int id;
+ if (int.TryParse(itemm.GetAttribute("id", ""), out id) == false)
+ continue; // wtf?
+ var captured = itemm;
+ var cacheValues = GetCacheValues(id, idd => ConvertFromXPathNavigator(captured));
+ mediaList.Add(CreateFromCacheValues(cacheValues));
+ }
+
+ return mediaList;
+ }
+
+
+ internal XPathNodeIterator GetMediaXPathNodeIterator(int mediaId, bool deep)
+ {
+ var media = Current.Services.MediaService.GetById(mediaId);
+ if (media == null) return null;
+
+ var serialized = EntityXmlSerializer.Serialize(
+ Current.Services.MediaService,
+ Current.Services.DataTypeService,
+ Current.Services.UserService,
+ Current.Services.LocalizationService,
+ Current.UrlSegmentProviders,
+ media,
+ deep);
+
+ return serialized.CreateNavigator().Select("/");
+ }
+
+
+
+ internal void Resync()
+ {
+ // clear recursive properties cached by XmlPublishedContent.GetProperty
+ // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch)
+ // NOTE all properties cleared when clearing the content cache (see content cache)
+ //_cacheProvider.ClearCacheObjectTypes();
+ //_cacheProvider.ClearCacheByKeySearch("XmlPublishedCache.PublishedMediaCache:RecursiveProperty-");
+ }
+
+ #region Content types
+
+ public override PublishedContentType GetContentType(int id)
+ {
+ return _contentTypeCache.Get(PublishedItemType.Media, id);
+ }
+
+ public override PublishedContentType GetContentType(string alias)
+ {
+ return _contentTypeCache.Get(PublishedItemType.Media, alias);
+ }
+
+ public override IEnumerable GetByContentType(PublishedContentType contentType)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ // REFACTORING
+
+ // caching the basic atomic values - and the parent id
+ // but NOT caching actual parent nor children and NOT even
+ // the list of children ids - BUT caching the path
+
+ internal class CacheValues
+ {
+ public IReadOnlyDictionary Values { get; set; }
+ public XPathNavigator XPath { get; set; }
+ public bool FromExamine { get; set; }
+ }
+
+ public const string PublishedMediaCacheKey = "MediaCacheMeh.";
+ private const int PublishedMediaCacheTimespanSeconds = 4 * 60; // 4 mins
+ private static TimeSpan _publishedMediaCacheTimespan;
+ private static bool _publishedMediaCacheEnabled;
+
+ private static void InitializeCacheConfig()
+ {
+ var value = ConfigurationManager.AppSettings["Umbraco.PublishedMediaCache.Seconds"];
+ int seconds;
+ if (int.TryParse(value, out seconds) == false)
+ seconds = PublishedMediaCacheTimespanSeconds;
+ if (seconds > 0)
+ {
+ _publishedMediaCacheEnabled = true;
+ _publishedMediaCacheTimespan = TimeSpan.FromSeconds(seconds);
+ }
+ else
+ {
+ _publishedMediaCacheEnabled = false;
+ }
+ }
+
+ internal IPublishedContent CreateFromCacheValues(CacheValues cacheValues)
+ {
+ var content = new DictionaryPublishedContent(
+ cacheValues.Values,
+ parentId => parentId < 0 ? null : GetUmbracoMedia(parentId),
+ GetChildrenMedia,
+ GetProperty,
+ _cacheProvider,
+ _contentTypeCache,
+ cacheValues.XPath, // though, outside of tests, that should be null
+ cacheValues.FromExamine
+ );
+ return content.CreateModel();
+ }
+
+ private static CacheValues GetCacheValues(int id, Func func)
+ {
+ if (_publishedMediaCacheEnabled == false)
+ return func(id);
+
+ var cache = Current.ApplicationCache.RuntimeCache;
+ var key = PublishedMediaCacheKey + id;
+ return (CacheValues)cache.GetCacheItem(key, () => func(id), _publishedMediaCacheTimespan);
+ }
+
+ internal static void ClearCache(int id)
+ {
+ var cache = Current.ApplicationCache.RuntimeCache;
+ var sid = id.ToString();
+ var key = PublishedMediaCacheKey + sid;
+
+ // we do clear a lot of things... but the cache refresher is somewhat
+ // convoluted and it's hard to tell what to clear exactly ;-(
+
+ // clear the parent - NOT (why?)
+ //var exist = (CacheValues) cache.GetCacheItem(key);
+ //if (exist != null)
+ // cache.ClearCacheItem(PublishedMediaCacheKey + GetValuesValue(exist.Values, "parentID"));
+
+ // clear the item
+ cache.ClearCacheItem(key);
+
+ // clear all children - in case we moved and their path has changed
+ var fid = "/" + sid + "/";
+ cache.ClearCacheObjectTypes((k, v) =>
+ GetValuesValue(v.Values, "path", "__Path").Contains(fid));
+ }
+
+ private static string GetValuesValue(IReadOnlyDictionary d, params string[] keys)
+ {
+ string value = null;
+ var ignored = keys.Any(x => d.TryGetValue(x, out value));
+ return value ?? "";
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index f9708e5c04..5e59dcc996 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -1,1585 +1,1582 @@
-
-
-
-
- v4.7.2
- false
- false
- {651E1350-91B6-44B7-BD60-7207006D7003}
- Library
- Umbraco.Web
- Umbraco.Web
- ..\
- true
- Off
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- false
- latest
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- bin\Release\Umbraco.Web.xml
- false
- latest
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {31785bc3-256c-4613-b2f5-a1b0bdded8c1}
- Umbraco.Core
-
-
- Umbraco.Examine
- {07FBC26B-2927-4A22-8D96-D644C667FECC}
-
-
-
-
-
-
- Properties\SolutionInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
-
-
- True
- True
- Reference.map
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- Resources.resx
-
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- AssignDomain2.aspx
- ASPXCodeBehind
-
-
- AssignDomain2.aspx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- Strings.resx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
- Code
-
-
- Code
-
-
- Code
-
-
- True
- True
- Settings.settings
-
-
- Code
-
-
-
-
- ASPXCodeBehind
-
-
- Component
-
-
-
-
- Code
-
-
-
-
-
-
- FeedProxy.aspx
- ASPXCodeBehind
-
-
- FeedProxy.aspx
-
-
- EditRelationType.aspx
-
-
- EditRelationType.aspx
-
-
- NewRelationType.aspx
- ASPXCodeBehind
-
-
- NewRelationType.aspx
-
-
- RelationTypesWebService.asmx
- Component
-
-
-
-
- Preview.aspx
- ASPXCodeBehind
-
-
- Preview.aspx
-
-
- insertMasterpageContent.aspx
- ASPXCodeBehind
-
-
- insertMasterpageContent.aspx
-
-
- insertMasterpagePlaceholder.aspx
- ASPXCodeBehind
-
-
- insertMasterpagePlaceholder.aspx
-
-
- republish.aspx
-
-
- republish.aspx
-
-
- SendPublish.aspx
- ASPXCodeBehind
-
-
- SendPublish.aspx
-
-
- Code
-
-
- editPackage.aspx
- ASPXCodeBehind
-
-
- editPackage.aspx
-
-
- exportDocumenttype.aspx
- ASPXCodeBehind
-
-
- importDocumenttype.aspx
- ASPXCodeBehind
-
-
- notifications.aspx
- ASPXCodeBehind
-
-
- notifications.aspx
-
-
- rollBack.aspx
-
-
- rollBack.aspx
-
-
- sendToTranslation.aspx
- ASPXCodeBehind
-
-
- sendToTranslation.aspx
-
-
- viewAuditTrail.aspx
- ASPXCodeBehind
-
-
- viewAuditTrail.aspx
-
-
- DictionaryItemList.aspx
- ASPXCodeBehind
-
-
- DictionaryItemList.aspx
-
-
- EditDictionaryItem.aspx
- ASPXCodeBehind
-
-
- EditDictionaryItem.aspx
-
-
- Code
-
-
-
-
-
-
-
-
-
-
- default.aspx
- ASPXCodeBehind
-
-
- default.aspx
-
-
- details.aspx
- ASPXCodeBehind
-
-
- details.aspx
-
-
- preview.aspx
- ASPXCodeBehind
-
-
- preview.aspx
-
-
- xml.aspx
- ASPXCodeBehind
-
-
- xml.aspx
-
-
-
-
-
-
-
-
-
-
-
- CheckForUpgrade.asmx
- Component
-
-
- legacyAjaxCalls.asmx
- Component
-
-
- nodeSorter.asmx
- Component
-
-
- ASPXCodeBehind
-
-
-
-
-
-
- True
- True
- Reference.map
-
-
-
-
-
-
-
-
-
-
- Component
-
-
-
- Component
-
-
-
-
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
- Designer
-
-
- ResXFileCodeGenerator
- Strings.Designer.cs
-
-
-
-
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
-
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
-
-
- ASPXCodeBehind
-
-
- ASPXCodeBehind
-
-
-
- ASPXCodeBehind
-
-
-
-
-
-
- MSDiscoCodeGenerator
- Reference.cs
- Designer
-
-
- Mvc\web.config
-
-
- MSDiscoCodeGenerator
- Reference.cs
-
-
-
-
- Reference.map
-
-
- Reference.map
-
-
- SettingsSingleFileGenerator
- Settings1.Designer.cs
-
-
-
-
- Dynamic
- Web References\org.umbraco.our\
- http://our.umbraco.org/umbraco/webservices/api/repository.asmx
-
-
-
-
- Settings
- umbraco_org_umbraco_our_Repository
-
-
- Dynamic
- Web References\org.umbraco.update\
- http://update.umbraco.org/checkforupgrade.asmx
-
-
-
-
- Settings
- umbraco_org_umbraco_update_CheckForUpgrade
-
-
-
-
-
-
- $(PlatformTargetAsMSBuildArchitecture)
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ v4.7.2
+ false
+ false
+ {651E1350-91B6-44B7-BD60-7207006D7003}
+ Library
+ Umbraco.Web
+ Umbraco.Web
+ ..\
+ true
+ Off
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+ latest
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ bin\Release\Umbraco.Web.xml
+ false
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {31785bc3-256c-4613-b2f5-a1b0bdded8c1}
+ Umbraco.Core
+
+
+ Umbraco.Examine
+ {07FBC26B-2927-4A22-8D96-D644C667FECC}
+
+
+
+
+
+
+ Properties\SolutionInfo.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+ True
+ True
+ Reference.map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ AssignDomain2.aspx
+ ASPXCodeBehind
+
+
+ AssignDomain2.aspx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Strings.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ True
+ True
+ Settings.settings
+
+
+ Code
+
+
+
+
+ ASPXCodeBehind
+
+
+ Component
+
+
+
+
+ Code
+
+
+
+
+
+
+ FeedProxy.aspx
+ ASPXCodeBehind
+
+
+ FeedProxy.aspx
+
+
+ EditRelationType.aspx
+
+
+ EditRelationType.aspx
+
+
+ NewRelationType.aspx
+ ASPXCodeBehind
+
+
+ NewRelationType.aspx
+
+
+ RelationTypesWebService.asmx
+ Component
+
+
+
+
+ Preview.aspx
+ ASPXCodeBehind
+
+
+ Preview.aspx
+
+
+ insertMasterpageContent.aspx
+ ASPXCodeBehind
+
+
+ insertMasterpageContent.aspx
+
+
+ insertMasterpagePlaceholder.aspx
+ ASPXCodeBehind
+
+
+ insertMasterpagePlaceholder.aspx
+
+
+ republish.aspx
+
+
+ republish.aspx
+
+
+ SendPublish.aspx
+ ASPXCodeBehind
+
+
+ SendPublish.aspx
+
+
+ Code
+
+
+ editPackage.aspx
+ ASPXCodeBehind
+
+
+ editPackage.aspx
+
+
+ exportDocumenttype.aspx
+ ASPXCodeBehind
+
+
+ importDocumenttype.aspx
+ ASPXCodeBehind
+
+
+ notifications.aspx
+ ASPXCodeBehind
+
+
+ notifications.aspx
+
+
+ rollBack.aspx
+
+
+ rollBack.aspx
+
+
+ sendToTranslation.aspx
+ ASPXCodeBehind
+
+
+ sendToTranslation.aspx
+
+
+ viewAuditTrail.aspx
+ ASPXCodeBehind
+
+
+ viewAuditTrail.aspx
+
+
+ DictionaryItemList.aspx
+ ASPXCodeBehind
+
+
+ DictionaryItemList.aspx
+
+
+ EditDictionaryItem.aspx
+ ASPXCodeBehind
+
+
+ EditDictionaryItem.aspx
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
+ default.aspx
+ ASPXCodeBehind
+
+
+ default.aspx
+
+
+ details.aspx
+ ASPXCodeBehind
+
+
+ details.aspx
+
+
+ preview.aspx
+ ASPXCodeBehind
+
+
+ preview.aspx
+
+
+ xml.aspx
+ ASPXCodeBehind
+
+
+ xml.aspx
+
+
+
+
+
+
+
+
+
+
+
+ CheckForUpgrade.asmx
+ Component
+
+
+ legacyAjaxCalls.asmx
+ Component
+
+
+ nodeSorter.asmx
+ Component
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+ True
+ True
+ Reference.map
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+
+ Component
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ Strings.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+
+
+ ASPXCodeBehind
+
+
+ ASPXCodeBehind
+
+
+
+ ASPXCodeBehind
+
+
+
+
+
+
+ MSDiscoCodeGenerator
+ Reference.cs
+ Designer
+
+
+ Mvc\web.config
+
+
+ MSDiscoCodeGenerator
+ Reference.cs
+
+
+
+
+ Reference.map
+
+
+ Reference.map
+
+
+ SettingsSingleFileGenerator
+ Settings1.Designer.cs
+
+
+
+
+ Dynamic
+ Web References\org.umbraco.our\
+ http://our.umbraco.org/umbraco/webservices/api/repository.asmx
+
+
+
+
+ Settings
+ umbraco_org_umbraco_our_Repository
+
+
+ Dynamic
+ Web References\org.umbraco.update\
+ http://update.umbraco.org/checkforupgrade.asmx
+
+
+
+
+ Settings
+ umbraco_org_umbraco_update_CheckForUpgrade
+
+
+
+
+
+
+ $(PlatformTargetAsMSBuildArchitecture)
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs
deleted file mode 100644
index d76b4066f6..0000000000
--- a/src/Umbraco.Web/umbraco.presentation/library.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using System.Xml.Linq;
-using System.Xml.XPath;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Services;
-using Umbraco.Web.Composing;
-
-namespace umbraco
-{
- ///
- /// Function library for umbraco. Includes various helper-methods and methods to
- /// save and load data from umbraco.
- ///
- /// Especially usefull in XSLT where any of these methods can be accesed using the umbraco.library name-space. Example:
- /// <xsl:value-of select="umbraco.library:NiceUrl(@id)"/>
- ///
- [Obsolete("v8.kill.kill")]
- public class library
- {
- ///
- /// Get a media object as an xml object
- ///
- /// The identifier of the media object to be returned
- /// If true, children of the media object is returned
- /// An umbraco xml node of the media (same format as a document node)
- public static XPathNodeIterator GetMedia(int MediaId, bool deep)
- {
- try
- {
- if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration > 0)
- {
- var xml = Current.ApplicationCache.RuntimeCache.GetCacheItem(
- $"{CacheKeys.MediaCacheKey}_{MediaId}_{deep}",
- timeout: TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration),
- getCacheItem: () => GetMediaDo(MediaId, deep).Item1);
-
- if (xml != null)
- {
- //returning the root element of the Media item fixes the problem
- return xml.CreateNavigator().Select("/");
- }
-
- }
- else
- {
- var xml = GetMediaDo(MediaId, deep).Item1;
-
- //returning the root element of the Media item fixes the problem
- return xml.CreateNavigator().Select("/");
- }
- }
- catch(Exception ex)
- {
- Current.Logger.Error("An error occurred looking up media", ex);
- }
-
- Current.Logger.Debug(() => $"No media result for id {MediaId}");
-
- var errorXml = new XElement("error", string.Format("No media is maching '{0}'", MediaId));
- return errorXml.CreateNavigator().Select("/");
- }
-
-
- private static Tuple GetMediaDo(int mediaId, bool deep)
- {
- var media = Current.Services.MediaService.GetById(mediaId);
- if (media == null) return null;
-
- var serialized = EntityXmlSerializer.Serialize(
- Current.Services.MediaService,
- Current.Services.DataTypeService,
- Current.Services.UserService,
- Current.Services.LocalizationService,
- Current.UrlSegmentProviders,
- media,
- deep);
- return Tuple.Create(serialized, media.Path);
- }
- }
-}