diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec
index 7199f414b1..969ac5be3d 100644
--- a/build/NuSpecs/UmbracoCms.Web.nuspec
+++ b/build/NuSpecs/UmbracoCms.Web.nuspec
@@ -25,7 +25,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
-
+
diff --git a/build/build-bootstrap.ps1 b/build/build-bootstrap.ps1
index 71a25bfd7e..82c789ff22 100644
--- a/build/build-bootstrap.ps1
+++ b/build/build-bootstrap.ps1
@@ -22,6 +22,8 @@
# get NuGet
$cache = 4
$nuget = "$scriptTemp\nuget.exe"
+ # ensure the correct NuGet-source is used. This one is used by Umbraco
+ $nugetsourceUmbraco = "https://www.myget.org/F/umbracocore/api/v3/index.json"
if (-not $local)
{
$source = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
@@ -61,7 +63,7 @@
# get the build system
if (-not $local)
{
- $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease"
+ $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease", "-Source", $nugetsourceUmbraco
&$nuget install Umbraco.Build @params
if (-not $?) { throw "Failed to download Umbraco.Build." }
}
diff --git a/build/build.ps1 b/build/build.ps1
index ea07e4516f..6e124d1508 100644
--- a/build/build.ps1
+++ b/build/build.ps1
@@ -375,11 +375,14 @@
})
+ $nugetsourceUmbraco = "https://api.nuget.org/v3/index.json"
+
$ubuild.DefineMethod("RestoreNuGet",
{
Write-Host "Restore NuGet"
Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log"
- &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log"
+ $params = "-Source", $nugetsourceUmbraco
+ &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" @params
if (-not $?) { throw "Failed to restore NuGet packages." }
})
diff --git a/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs
new file mode 100644
index 0000000000..1e9f7976d5
--- /dev/null
+++ b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs
@@ -0,0 +1,50 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Configuration.Models;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.HealthChecks;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using ConnectionStrings = Umbraco.Configuration.Models.ConnectionStrings;
+using CoreDebugSettings = Umbraco.Configuration.Models.CoreDebugSettings;
+
+namespace Umbraco.Configuration
+{
+ public class AspNetCoreConfigsFactory : IConfigsFactory
+ {
+ private readonly IConfiguration _configuration;
+
+ public AspNetCoreConfigsFactory(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public Configs Create()
+ {
+ var configs = new Configs();
+
+ configs.Add(() => new TourSettings(_configuration));
+ configs.Add(() => new CoreDebugSettings(_configuration));
+ configs.Add(() => new RequestHandlerSettings(_configuration));
+ configs.Add(() => new SecuritySettings(_configuration));
+ configs.Add(() => new UserPasswordConfigurationSettings(_configuration));
+ configs.Add(() => new MemberPasswordConfigurationSettings(_configuration));
+ configs.Add(() => new KeepAliveSettings(_configuration));
+ configs.Add(() => new ContentSettings(_configuration));
+ configs.Add(() => new HealthChecksSettings(_configuration));
+ configs.Add(() => new LoggingSettings(_configuration));
+ configs.Add(() => new ExceptionFilterSettings(_configuration));
+ configs.Add(() => new ActiveDirectorySettings(_configuration));
+ configs.Add(() => new RuntimeSettings(_configuration));
+ configs.Add(() => new TypeFinderSettings(_configuration));
+ configs.Add(() => new NuCacheSettings(_configuration));
+ configs.Add(() => new WebRoutingSettings(_configuration));
+ configs.Add(() => new IndexCreatorSettings(_configuration));
+ configs.Add(() => new ModelsBuilderConfig(_configuration));
+ configs.Add(() => new HostingSettings(_configuration));
+ configs.Add(() => new GlobalSettings(_configuration));
+ configs.Add(() => new ConnectionStrings(_configuration));
+ configs.Add(() => new ImagingSettings(_configuration));
+
+ return configs;
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs b/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs
deleted file mode 100644
index f07e5133ef..0000000000
--- a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Globalization;
-using System.Linq;
-using System.Configuration;
-
-namespace Umbraco.Core.Configuration
-{
- ///
- /// A case-insensitive configuration converter for enumerations.
- ///
- /// The type of the enumeration.
- public class CaseInsensitiveEnumConfigConverter : ConfigurationConverterBase
- where T : struct
- {
- public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
- {
- if (data == null)
- throw new ArgumentNullException("data");
-
- //return Enum.Parse(typeof(T), (string)data, true);
-
- T value;
- if (Enum.TryParse((string)data, true, out value))
- return value;
-
- throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.",
- data, typeof(T).Name,
- string.Join(", ", Enum.GetValues(typeof(T)).Cast())));
- }
- }
-}
diff --git a/src/Umbraco.Configuration/ConfigsFactory.cs b/src/Umbraco.Configuration/ConfigsFactory.cs
index 2ba3a109e1..be6cee2d0c 100644
--- a/src/Umbraco.Configuration/ConfigsFactory.cs
+++ b/src/Umbraco.Configuration/ConfigsFactory.cs
@@ -1,19 +1,16 @@
-using System.Configuration;
using Umbraco.Configuration;
using Umbraco.Configuration.Implementations;
+using Umbraco.Configuration.Legacy;
using Umbraco.Core.Configuration.HealthChecks;
+using Umbraco.Core.Configuration.Legacy;
using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.IO;
-using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
public class ConfigsFactory : IConfigsFactory
{
public IHostingSettings HostingSettings { get; } = new HostingSettings();
-
- public ICoreDebug CoreDebug { get; } = new CoreDebug();
- public IMachineKeyConfig MachineKeyConfig { get; } = new MachineKeyConfig();
+ public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings();
public IIndexCreatorSettings IndexCreatorSettings { get; } = new IndexCreatorSettings();
public INuCacheSettings NuCacheSettings { get; } = new NuCacheSettings();
public ITypeFinderSettings TypeFinderSettings { get; } = new TypeFinderSettings();
@@ -29,28 +26,27 @@ namespace Umbraco.Core.Configuration
public IUserPasswordConfiguration UserPasswordConfigurationSettings { get; } = new UserPasswordConfigurationSettings();
public IMemberPasswordConfiguration MemberPasswordConfigurationSettings { get; } = new MemberPasswordConfigurationSettings();
public IContentSettings ContentSettings { get; } = new ContentSettings();
+ public IGlobalSettings GlobalSettings { get; } = new GlobalSettings();
+ public IHealthChecksSettings HealthChecksSettings { get; } = new HealthChecksSettings();
+ public IConnectionStrings ConnectionStrings { get; } = new ConnectionStrings();
+ public IModelsBuilderConfig ModelsBuilderConfig { get; } = new ModelsBuilderConfig();
- public Configs Create(IIOHelper ioHelper, ILogger logger)
+ public Configs Create()
{
- var configs = new Configs(section => ConfigurationManager.GetSection(section));
- configs.Add(() => new GlobalSettings(ioHelper));
- configs.Add(() => HostingSettings);
-
- configs.Add("umbracoConfiguration/HealthChecks");
-
- configs.Add(() => CoreDebug);
- configs.Add(() => MachineKeyConfig);
- configs.Add(() => new ConnectionStrings(ioHelper, logger));
- configs.Add(() => new ModelsBuilderConfig(ioHelper));
-
+ var configs = new Configs();
+ configs.Add(() => GlobalSettings);
+ configs.Add(() => HostingSettings);
+ configs.Add(() => HealthChecksSettings);
+ configs.Add(() => CoreDebugSettings);
+ configs.Add(() => ConnectionStrings);
+ configs.Add(() => ModelsBuilderConfig);
configs.Add(() => IndexCreatorSettings);
configs.Add(() => NuCacheSettings);
configs.Add(() => TypeFinderSettings);
configs.Add(() => RuntimeSettings);
configs.Add(() => ActiveDirectorySettings);
configs.Add(() => ExceptionFilterSettings);
-
configs.Add(() => TourSettings);
configs.Add(() => LoggingSettings);
configs.Add(() => KeepAliveSettings);
@@ -61,7 +57,6 @@ namespace Umbraco.Core.Configuration
configs.Add(() => MemberPasswordConfigurationSettings);
configs.Add(() => ContentSettings);
- configs.AddCoreConfigs(ioHelper);
return configs;
}
}
diff --git a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
index 90a7d8c567..373d846567 100644
--- a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
+++ b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
@@ -1,10 +1,9 @@
using System;
-using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
- public class HealthChecksSection : ConfigurationSection, IHealthChecks
+ public class HealthChecksSection : ConfigurationSection
{
private const string DisabledChecksKey = "disabledChecks";
private const string NotificationSettingsKey = "notificationSettings";
@@ -21,14 +20,5 @@ namespace Umbraco.Core.Configuration.HealthChecks
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
}
- IEnumerable IHealthChecks.DisabledChecks
- {
- get { return DisabledChecks; }
- }
-
- IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
- {
- get { return NotificationSettings; }
- }
}
}
diff --git a/src/Umbraco.Configuration/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs
similarity index 90%
rename from src/Umbraco.Configuration/ActiveDirectorySettings.cs
rename to src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs
index d85def7f33..ef100afed6 100644
--- a/src/Umbraco.Configuration/ActiveDirectorySettings.cs
+++ b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class ActiveDirectorySettings : IActiveDirectorySettings
{
diff --git a/src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Implementations/ConfigurationManagerConfigBase.cs b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs
similarity index 90%
rename from src/Umbraco.Configuration/Implementations/ConfigurationManagerConfigBase.cs
rename to src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs
index d218ac803b..0302a7ea31 100644
--- a/src/Umbraco.Configuration/Implementations/ConfigurationManagerConfigBase.cs
+++ b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs
@@ -7,7 +7,7 @@ namespace Umbraco.Configuration.Implementations
{
private UmbracoSettingsSection _umbracoSettingsSection;
- public UmbracoSettingsSection UmbracoSettingsSection
+ protected UmbracoSettingsSection UmbracoSettingsSection
{
get
{
diff --git a/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs
new file mode 100644
index 0000000000..a02c351118
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs
@@ -0,0 +1,17 @@
+using System.Configuration;
+
+namespace Umbraco.Core.Configuration
+{
+ public class ConnectionStrings : IConnectionStrings
+ {
+ public ConfigConnectionString this[string key]
+ {
+ get
+ {
+ var settings = ConfigurationManager.ConnectionStrings[key];
+ if (settings == null) return null;
+ return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Implementations/ContentSettings.cs b/src/Umbraco.Configuration/Legacy/ContentSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/ContentSettings.cs
rename to src/Umbraco.Configuration/Legacy/ContentSettings.cs
diff --git a/src/Umbraco.Configuration/CoreDebug.cs b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
similarity index 87%
rename from src/Umbraco.Configuration/CoreDebug.cs
rename to src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
index 0ff3274565..4902d4489f 100644
--- a/src/Umbraco.Configuration/CoreDebug.cs
+++ b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
@@ -3,9 +3,9 @@ using System.Configuration;
namespace Umbraco.Core.Configuration
{
- public class CoreDebug : ICoreDebug
+ public class CoreDebugSettings : ICoreDebugSettings
{
- public CoreDebug()
+ public CoreDebugSettings()
{
var appSettings = ConfigurationManager.AppSettings;
LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase);
diff --git a/src/Umbraco.Configuration/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs
similarity index 92%
rename from src/Umbraco.Configuration/ExceptionFilterSettings.cs
rename to src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs
index 628b8755cc..50e2207485 100644
--- a/src/Umbraco.Configuration/ExceptionFilterSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class ExceptionFilterSettings : IExceptionFilterSettings
{
diff --git a/src/Umbraco.Configuration/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
similarity index 87%
rename from src/Umbraco.Configuration/GlobalSettings.cs
rename to src/Umbraco.Configuration/Legacy/GlobalSettings.cs
index 923cd422bf..78036f9e42 100644
--- a/src/Umbraco.Configuration/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
@@ -3,59 +3,12 @@ using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Xml.Linq;
+using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core.IO;
-namespace Umbraco.Core.Configuration
+namespace Umbraco.Core.Configuration.Legacy
{
- public class HostingSettings : IHostingSettings
- {
- private bool? _debugMode;
-
- ///
- public LocalTempStorage LocalTempStorageLocation
- {
- get
- {
- var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
- if (!string.IsNullOrWhiteSpace(setting))
- return Enum.Parse(setting);
-
- return LocalTempStorage.Default;
- }
- }
-
- ///
- /// Gets a value indicating whether umbraco is running in [debug mode].
- ///
- /// true if [debug mode]; otherwise, false.
- public bool DebugMode
- {
- get
- {
- if (!_debugMode.HasValue)
- {
- try
- {
- if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation)
- {
- var debugElement = compilation.ElementInformation.Properties["debug"];
-
- _debugMode = debugElement != null && (debugElement.Value is bool debug && debug);
-
- }
- }
- catch
- {
- _debugMode = false;
- }
- }
-
- return _debugMode.GetValueOrDefault();
- }
- }
- }
-
// TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults!
// TODO: need to massively cleanup these configuration classes
@@ -64,7 +17,6 @@ namespace Umbraco.Core.Configuration
///
public class GlobalSettings : IGlobalSettings
{
- private readonly IIOHelper _ioHelper;
// TODO these should not be static
private static string _reservedPaths;
@@ -74,11 +26,6 @@ namespace Umbraco.Core.Configuration
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
- public GlobalSettings(IIOHelper ioHelper)
- {
- _ioHelper = ioHelper;
- }
-
///
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
///
@@ -203,15 +150,7 @@ namespace Umbraco.Core.Configuration
/// Gets the path to umbraco's root directory (/umbraco by default).
///
/// The path.
- public string Path
- {
- get
- {
- return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path)
- ? _ioHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path])
- : string.Empty;
- }
- }
+ public string Path => ConfigurationManager.AppSettings[Constants.AppSettings.Path];
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
@@ -227,7 +166,7 @@ namespace Umbraco.Core.Configuration
}
set
{
- SaveSetting(Constants.AppSettings.ConfigurationStatus, value, _ioHelper);
+ SaveSetting(Constants.AppSettings.ConfigurationStatus, value, Current.IOHelper); //TODO remove
}
}
@@ -254,7 +193,7 @@ namespace Umbraco.Core.Configuration
ConfigurationManager.RefreshSection("appSettings");
}
-
+
///
/// Gets the time out in minutes.
///
diff --git a/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs
new file mode 100644
index 0000000000..23385d1378
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Configuration;
+using Umbraco.Core.Configuration.HealthChecks;
+
+namespace Umbraco.Core.Configuration.Legacy
+{
+ public class HealthChecksSettings : IHealthChecksSettings
+ {
+ private HealthChecksSection _healthChecksSection;
+
+ private HealthChecksSection HealthChecksSection
+ {
+ get
+ {
+ if (_healthChecksSection is null)
+ {
+ _healthChecksSection = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as HealthChecksSection;
+ }
+ return _healthChecksSection;
+ }
+ }
+
+ public IEnumerable DisabledChecks => HealthChecksSection.DisabledChecks;
+ public IHealthCheckNotificationSettings NotificationSettings => HealthChecksSection.NotificationSettings;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/HostingSettings.cs b/src/Umbraco.Configuration/Legacy/HostingSettings.cs
new file mode 100644
index 0000000000..d0d09ea86f
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/HostingSettings.cs
@@ -0,0 +1,52 @@
+using System.Configuration;
+
+namespace Umbraco.Core.Configuration.Legacy
+{
+ public class HostingSettings : IHostingSettings
+ {
+ private bool? _debugMode;
+
+ ///
+ public LocalTempStorage LocalTempStorageLocation
+ {
+ get
+ {
+ var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
+ if (!string.IsNullOrWhiteSpace(setting))
+ return Enum.Parse(setting);
+
+ return LocalTempStorage.Default;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco is running in [debug mode].
+ ///
+ /// true if [debug mode]; otherwise, false.
+ public bool DebugMode
+ {
+ get
+ {
+ if (!_debugMode.HasValue)
+ {
+ try
+ {
+ if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation)
+ {
+ var debugElement = compilation.ElementInformation.Properties["debug"];
+
+ _debugMode = debugElement != null && (debugElement.Value is bool debug && debug);
+
+ }
+ }
+ catch
+ {
+ _debugMode = false;
+ }
+ }
+
+ return _debugMode.GetValueOrDefault();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs
similarity index 78%
rename from src/Umbraco.Configuration/IndexCreatorSettings.cs
rename to src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs
index 00d1a29dba..d023d46246 100644
--- a/src/Umbraco.Configuration/IndexCreatorSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs
@@ -1,13 +1,13 @@
using System.Configuration;
using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class IndexCreatorSettings : IIndexCreatorSettings
{
public IndexCreatorSettings()
{
- LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"];
+ LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"];
}
public string LuceneDirectoryFactory { get; }
diff --git a/src/Umbraco.Configuration/InnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/InnerTextConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Implementations/KeepAliveSettings.cs b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/KeepAliveSettings.cs
rename to src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs
diff --git a/src/Umbraco.Configuration/Implementations/LoggingSettings.cs b/src/Umbraco.Configuration/Legacy/LoggingSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/LoggingSettings.cs
rename to src/Umbraco.Configuration/Legacy/LoggingSettings.cs
diff --git a/src/Umbraco.Configuration/Implementations/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/MemberPasswordConfigurationSettings.cs
rename to src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs
diff --git a/src/Umbraco.Configuration/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
similarity index 80%
rename from src/Umbraco.Configuration/ModelsBuilderConfig.cs
rename to src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
index 151e9908a1..f6395b23b4 100644
--- a/src/Umbraco.Configuration/ModelsBuilderConfig.cs
+++ b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
@@ -6,14 +6,14 @@ using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.IO;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
///
/// Represents the models builder configuration.
///
public class ModelsBuilderConfig : IModelsBuilderConfig
{
- private readonly IIOHelper _ioHelper;
+
private const string Prefix = "Umbraco.ModelsBuilder.";
private object _modelsModelLock;
private bool _modelsModelConfigured;
@@ -23,15 +23,13 @@ namespace Umbraco.Configuration
private bool _flagOutOfDateModels;
- public string DefaultModelsDirectory => _ioHelper.MapPath("~/App_Data/Models");
+ public string DefaultModelsDirectory => "~/App_Data/Models";
///
/// Initializes a new instance of the class.
///
- public ModelsBuilderConfig(IIOHelper ioHelper)
+ public ModelsBuilderConfig()
{
- _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
-
// giant kill switch, default: false
// must be explicitely set to true for anything else to happen
Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true";
@@ -59,12 +57,8 @@ namespace Umbraco.Configuration
value = ConfigurationManager.AppSettings[Prefix + "ModelsDirectory"];
if (!string.IsNullOrWhiteSpace(value))
{
- var root = _ioHelper.MapPath("~/");
- if (root == null)
- throw new ConfigurationErrorsException("Could not determine root directory.");
-
// GetModelsDirectory will ensure that the path is safe
- ModelsDirectory = GetModelsDirectory(root, value, AcceptUnsafeModelsDirectory);
+ ModelsDirectory = value;
}
// default: 0
@@ -81,7 +75,7 @@ namespace Umbraco.Configuration
///
/// Initializes a new instance of the class.
///
- public ModelsBuilderConfig(IIOHelper ioHelper,
+ public ModelsBuilderConfig(
bool enable = false,
ModelsMode modelsMode = ModelsMode.Nothing,
string modelsNamespace = null,
@@ -91,7 +85,6 @@ namespace Umbraco.Configuration
bool acceptUnsafeModelsDirectory = false,
int debugLevel = 0)
{
- _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
Enable = enable;
_modelsMode = modelsMode;
@@ -103,36 +96,7 @@ namespace Umbraco.Configuration
DebugLevel = debugLevel;
}
- // internal for tests
- internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe)
- {
- // making sure it is safe, ie under the website root,
- // unless AcceptUnsafeModelsDirectory and then everything is OK.
- if (!Path.IsPathRooted(root))
- throw new ConfigurationErrorsException($"Root is not rooted \"{root}\".");
-
- if (config.StartsWith("~/"))
- {
- var dir = Path.Combine(root, config.TrimStart("~/"));
-
- // sanitize - GetFullPath will take care of any relative
- // segments in path, eg '../../foo.tmp' - it may throw a SecurityException
- // if the combined path reaches illegal parts of the filesystem
- dir = Path.GetFullPath(dir);
- root = Path.GetFullPath(root);
-
- if (!dir.StartsWith(root) && !acceptUnsafe)
- throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
-
- return dir;
- }
-
- if (acceptUnsafe)
- return Path.GetFullPath(config);
-
- throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
- }
///
/// Gets a value indicating whether the whole models experience is enabled.
diff --git a/src/Umbraco.Configuration/NuCacheSettings.cs b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs
similarity index 89%
rename from src/Umbraco.Configuration/NuCacheSettings.cs
rename to src/Umbraco.Configuration/Legacy/NuCacheSettings.cs
index c3a286d33d..25f52a5c7d 100644
--- a/src/Umbraco.Configuration/NuCacheSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class NuCacheSettings : INuCacheSettings
{
diff --git a/src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/RawXmlConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/RawXmlConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Implementations/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/RequestHandlerSettings.cs
rename to src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs
diff --git a/src/Umbraco.Configuration/RuntimeSettings.cs b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs
similarity index 96%
rename from src/Umbraco.Configuration/RuntimeSettings.cs
rename to src/Umbraco.Configuration/Legacy/RuntimeSettings.cs
index 6dc8d6f832..200642a819 100644
--- a/src/Umbraco.Configuration/RuntimeSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class RuntimeSettings : IRuntimeSettings
{
@@ -24,6 +24,6 @@ namespace Umbraco.Configuration
}
public int? MaxQueryStringLength { get; }
public int? MaxRequestLength { get; }
-
+
}
}
diff --git a/src/Umbraco.Configuration/Implementations/SecuritySettings.cs b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/SecuritySettings.cs
rename to src/Umbraco.Configuration/Legacy/SecuritySettings.cs
diff --git a/src/Umbraco.Configuration/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/SmtpSettings.cs
rename to src/Umbraco.Configuration/Legacy/SmtpSettings.cs
diff --git a/src/Umbraco.Configuration/Implementations/TourSettings.cs b/src/Umbraco.Configuration/Legacy/TourSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/TourSettings.cs
rename to src/Umbraco.Configuration/Legacy/TourSettings.cs
diff --git a/src/Umbraco.Configuration/TypeFinderSettings.cs b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs
similarity index 91%
rename from src/Umbraco.Configuration/TypeFinderSettings.cs
rename to src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs
index bb3063d7bf..b1009f754b 100644
--- a/src/Umbraco.Configuration/TypeFinderSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs
@@ -1,8 +1,8 @@
using System.Configuration;
-using Umbraco.Core.Configuration;
using Umbraco.Core;
+using Umbraco.Core.Configuration;
-namespace Umbraco.Configuration
+namespace Umbraco.Configuration.Legacy
{
public class TypeFinderSettings : ITypeFinderSettings
{
diff --git a/src/Umbraco.Configuration/UmbracoConfigurationSection.cs b/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs
similarity index 100%
rename from src/Umbraco.Configuration/UmbracoConfigurationSection.cs
rename to src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs
diff --git a/src/Umbraco.Configuration/Implementations/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/UserPasswordConfigurationSettings.cs
rename to src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs
diff --git a/src/Umbraco.Configuration/Implementations/WebRoutingSettings.cs b/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/Implementations/WebRoutingSettings.cs
rename to src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs
diff --git a/src/Umbraco.Configuration/MachineKeyConfig.cs b/src/Umbraco.Configuration/MachineKeyConfig.cs
deleted file mode 100644
index 4e3401e015..0000000000
--- a/src/Umbraco.Configuration/MachineKeyConfig.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Configuration;
-using Umbraco.Core.Configuration;
-
-namespace Umbraco.Configuration
-{
- public class MachineKeyConfig : IMachineKeyConfig
- {
- //TODO all the machineKey stuff should be replaced: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/replacing-machinekey?view=aspnetcore-3.1
-
- public bool HasMachineKey
- {
- get
- {
- var machineKeySection =
- ConfigurationManager.GetSection("system.web/machineKey") as ConfigurationSection;
- return !(machineKeySection?.ElementInformation?.Source is null);
- }
- }
- }
-}
diff --git a/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs
new file mode 100644
index 0000000000..015fb17a8e
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ActiveDirectorySettings : IActiveDirectorySettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "ActiveDirectory:";
+ private readonly IConfiguration _configuration;
+
+ public ActiveDirectorySettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string ActiveDirectoryDomain => _configuration.GetValue(Prefix+"Domain");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Configuration/Models/ConnectionStrings.cs
new file mode 100644
index 0000000000..9fc546a88f
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ConnectionStrings.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Linq;
+using System.Text.Json.Serialization;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ConnectionStrings : IConnectionStrings
+ {
+ private readonly IConfiguration _configuration;
+
+ public ConnectionStrings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public ConfigConnectionString this[string key]
+ {
+ get => new ConfigConnectionString(_configuration.GetConnectionString(key), "System.Data.SqlClient", key);
+ set => throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ContentSettings.cs b/src/Umbraco.Configuration/Models/ContentSettings.cs
new file mode 100644
index 0000000000..5bc31814b7
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ContentSettings.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ContentSettings : IContentSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Content:";
+ private const string NotificationsPrefix = Prefix + "Notifications:";
+ private const string ImagingPrefix = Prefix + "Imaging:";
+ private const string DefaultPreviewBadge =
+ @"";
+
+ private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField =
+ {
+ new ImagingAutoFillUploadField
+ {
+ Alias = "umbracoFile"
+ }
+ };
+
+ private readonly IConfiguration _configuration;
+
+ public ContentSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string NotificationEmailAddress =>
+ _configuration.GetValue(NotificationsPrefix+"Email");
+
+ public bool DisableHtmlEmail =>
+ _configuration.GetValue(NotificationsPrefix+"DisableHtmlEmail", false);
+
+ public IEnumerable ImageFileTypes => _configuration.GetValue(
+ ImagingPrefix+"ImageFileTypes", new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" });
+
+ public IEnumerable ImageAutoFillProperties =>
+ _configuration.GetValue(ImagingPrefix+"AutoFillImageProperties",
+ DefaultImagingAutoFillUploadField);
+
+
+ public bool ResolveUrlsFromTextString =>
+ _configuration.GetValue(Prefix+"ResolveUrlsFromTextString", false);
+
+ public IEnumerable Error404Collection => _configuration
+ .GetSection(Prefix+"Errors:Error404")
+ .GetChildren()
+ .Select(x => new ContentErrorPage(x));
+
+ public string PreviewBadge => _configuration.GetValue(Prefix+"PreviewBadge", DefaultPreviewBadge);
+
+ public MacroErrorBehaviour MacroErrorBehaviour =>
+ _configuration.GetValue(Prefix+"MacroErrors", MacroErrorBehaviour.Inline);
+
+ public IEnumerable DisallowedUploadFiles => _configuration.GetValue(
+ Prefix+"DisallowedUploadFiles",
+ new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" });
+
+ public IEnumerable AllowedUploadFiles =>
+ _configuration.GetValue(Prefix+"AllowedUploadFiles", Array.Empty());
+
+ public bool ShowDeprecatedPropertyEditors =>
+ _configuration.GetValue(Prefix+"ShowDeprecatedPropertyEditors", false);
+
+ public string LoginBackgroundImage =>
+ _configuration.GetValue(Prefix+"LoginBackgroundImage", string.Empty);
+
+ private class ContentErrorPage : IContentErrorPage
+ {
+ public ContentErrorPage(IConfigurationSection configurationSection)
+ {
+ Culture = configurationSection.Key;
+
+ var value = configurationSection.Value;
+
+ if (int.TryParse(value, out var contentId))
+ {
+ HasContentId = true;
+ ContentId = contentId;
+ }
+ else if (Guid.TryParse(value, out var contentKey))
+ {
+ HasContentKey = true;
+ ContentKey = contentKey;
+ }
+ else
+ {
+ ContentXPath = value;
+ }
+ }
+
+ public int ContentId { get; }
+ public Guid ContentKey { get; }
+ public string ContentXPath { get; }
+ public bool HasContentId { get; }
+ public bool HasContentKey { get; }
+ public string Culture { get; set; }
+ }
+
+ private class ImagingAutoFillUploadField : IImagingAutoFillUploadField
+ {
+ public string Alias { get; set; }
+ public string WidthFieldAlias { get; set; }
+ public string HeightFieldAlias { get; set; }
+ public string LengthFieldAlias { get; set; }
+ public string ExtensionFieldAlias { get; set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/CoreDebugSettings.cs b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs
new file mode 100644
index 0000000000..6d6c0eaf0d
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class CoreDebugSettings : ICoreDebugSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Core:Debug:";
+ private readonly IConfiguration _configuration;
+
+ public CoreDebugSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool LogUncompletedScopes =>
+ _configuration.GetValue(Prefix+"LogUncompletedScopes", false);
+
+ public bool DumpOnTimeoutThreadAbort =>
+ _configuration.GetValue(Prefix+"DumpOnTimeoutThreadAbort", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs
new file mode 100644
index 0000000000..581daf9f40
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ExceptionFilterSettings : IExceptionFilterSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "ExceptionFilter:";
+ private readonly IConfiguration _configuration;
+
+ public ExceptionFilterSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool Disabled => _configuration.GetValue(Prefix+"Disabled", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
new file mode 100644
index 0000000000..4dc764a974
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ ///
+ /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information
+ /// from web.config appsettings
+ ///
+ internal class GlobalSettings : IGlobalSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Global:";
+
+ internal const string
+ StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
+
+ internal const string
+ StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
+
+ private readonly IConfiguration _configuration;
+
+ public GlobalSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string ReservedUrls => _configuration.GetValue(Prefix + "ReservedUrls", StaticReservedUrls);
+ public string ReservedPaths => _configuration.GetValue(Prefix + "ReservedPaths", StaticReservedPaths);
+
+ public string Path => _configuration.GetValue(Prefix + "Path");
+
+ // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
+ public string ConfigurationStatus
+ {
+ get => _configuration.GetValue(Prefix + "ConfigurationStatus");
+ set => throw new NotImplementedException("We should remove this and only use the value from database");
+ }
+
+ public int TimeOutInMinutes => _configuration.GetValue(Prefix + "TimeOutInMinutes", 20);
+ public string DefaultUILanguage => _configuration.GetValue(Prefix + "TimeOutInMinutes", "en-US");
+
+ public bool HideTopLevelNodeFromPath =>
+ _configuration.GetValue(Prefix + "HideTopLevelNodeFromPath", false);
+
+ public bool UseHttps => _configuration.GetValue(Prefix + "UseHttps", false);
+ public int VersionCheckPeriod => _configuration.GetValue(Prefix + "VersionCheckPeriod", 7);
+ public string UmbracoPath => _configuration.GetValue(Prefix + "UmbracoPath", "~/umbraco");
+ public string UmbracoCssPath => _configuration.GetValue(Prefix + "UmbracoCssPath", "~/css");
+
+ public string UmbracoScriptsPath =>
+ _configuration.GetValue(Prefix + "UmbracoScriptsPath", "~/scripts");
+
+ public string UmbracoMediaPath => _configuration.GetValue(Prefix + "UmbracoMediaPath", "~/media");
+
+ public bool InstallMissingDatabase =>
+ _configuration.GetValue(Prefix + "InstallMissingDatabase", false);
+
+ public bool InstallEmptyDatabase => _configuration.GetValue(Prefix + "InstallEmptyDatabase", false);
+
+ public bool DisableElectionForSingleServer =>
+ _configuration.GetValue(Prefix + "DisableElectionForSingleServer", false);
+
+ public string RegisterType => _configuration.GetValue(Prefix + "RegisterType", string.Empty);
+
+ public string DatabaseFactoryServerVersion =>
+ _configuration.GetValue(Prefix + "DatabaseFactoryServerVersion", string.Empty);
+
+ public string MainDomLock => _configuration.GetValue(Prefix + "MainDomLock", string.Empty);
+
+ public string NoNodesViewPath =>
+ _configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml");
+
+ public bool IsSmtpServerConfigured =>
+ _configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false;
+
+ public ISmtpSettings SmtpSettings =>
+ new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp"));
+
+ private class SmtpSettingsImpl : ISmtpSettings
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public SmtpSettingsImpl(IConfigurationSection configurationSection)
+ {
+ _configurationSection = configurationSection;
+ }
+
+ public string From => _configurationSection.GetValue("From");
+ public string Host => _configurationSection.GetValue("Host");
+ public int Port => _configurationSection.GetValue("Port");
+ public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation");
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs
new file mode 100644
index 0000000000..1d73051ec8
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.HealthChecks;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class HealthChecksSettings : IHealthChecksSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "HealthChecks:";
+ private readonly IConfiguration _configuration;
+
+ public HealthChecksSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public IEnumerable DisabledChecks => _configuration
+ .GetSection(Prefix+"DisabledChecks")
+ .GetChildren()
+ .Select(
+ x => new DisabledHealthCheck
+ {
+ Id = x.GetValue("Id"),
+ DisabledOn = x.GetValue("DisabledOn"),
+ DisabledBy = x.GetValue("DisabledBy")
+ });
+
+ public IHealthCheckNotificationSettings NotificationSettings =>
+ new HealthCheckNotificationSettings(
+ _configuration.GetSection(Prefix+"NotificationSettings"));
+
+ private class DisabledHealthCheck : IDisabledHealthCheck
+ {
+ public Guid Id { get; set; }
+ public DateTime DisabledOn { get; set; }
+ public int DisabledBy { get; set; }
+ }
+
+ private class HealthCheckNotificationSettings : IHealthCheckNotificationSettings
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public HealthCheckNotificationSettings(IConfigurationSection configurationSection)
+ {
+ _configurationSection = configurationSection;
+ }
+
+ public bool Enabled => _configurationSection.GetValue("Enabled", false);
+ public string FirstRunTime => _configurationSection.GetValue("FirstRunTime");
+ public int PeriodInHours => _configurationSection.GetValue("PeriodInHours", 24);
+
+ public IReadOnlyDictionary NotificationMethods => _configurationSection
+ .GetSection("NotificationMethods")
+ .GetChildren()
+ .ToDictionary(x => x.Key, x => (INotificationMethod) new NotificationMethod(x.Key, x));
+
+ public IEnumerable DisabledChecks => _configurationSection
+ .GetSection("DisabledChecks").GetChildren().Select(
+ x => new DisabledHealthCheck
+ {
+ Id = x.GetValue("Id"),
+ DisabledOn = x.GetValue("DisabledOn"),
+ DisabledBy = x.GetValue("DisabledBy")
+ });
+ }
+
+ private class NotificationMethod : INotificationMethod
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public NotificationMethod(string alias, IConfigurationSection configurationSection)
+ {
+ Alias = alias;
+ _configurationSection = configurationSection;
+ }
+
+ public string Alias { get; }
+ public bool Enabled => _configurationSection.GetValue("Enabled", false);
+
+ public HealthCheckNotificationVerbosity Verbosity =>
+ _configurationSection.GetValue("Verbosity", HealthCheckNotificationVerbosity.Summary);
+
+ public bool FailureOnly => _configurationSection.GetValue("FailureOnly", true);
+
+ public IReadOnlyDictionary Settings => _configurationSection
+ .GetSection("Settings").GetChildren().ToDictionary(x => x.Key,
+ x => (INotificationMethodSettings) new NotificationMethodSettings(x.Key, x.Value));
+ }
+
+ private class NotificationMethodSettings : INotificationMethodSettings
+ {
+ public NotificationMethodSettings(string key, string value)
+ {
+ Key = key;
+ Value = value;
+ }
+
+ public string Key { get; }
+ public string Value { get; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/HostingSettings.cs b/src/Umbraco.Configuration/Models/HostingSettings.cs
new file mode 100644
index 0000000000..4a156cee6a
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/HostingSettings.cs
@@ -0,0 +1,27 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class HostingSettings : IHostingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Hosting:";
+ private readonly IConfiguration _configuration;
+
+ public HostingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ ///
+ public LocalTempStorage LocalTempStorageLocation =>
+ _configuration.GetValue(Prefix+"LocalTempStorage", LocalTempStorage.Default);
+
+ ///
+ /// Gets a value indicating whether umbraco is running in [debug mode].
+ ///
+ /// true if [debug mode]; otherwise, false.
+ public bool DebugMode => _configuration.GetValue(Prefix+":Debug", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ImagingSettings.cs b/src/Umbraco.Configuration/Models/ImagingSettings.cs
new file mode 100644
index 0000000000..4a9501b2ba
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ImagingSettings.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ImagingSettings : IImagingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Imaging:";
+ private const string CachePrefix = Prefix + "Cache:";
+ private const string ResizePrefix = Prefix + "Resize:";
+ private readonly IConfiguration _configuration;
+
+ public ImagingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int MaxBrowserCacheDays => _configuration.GetValue(CachePrefix + "MaxBrowserCacheDays", 7);
+ public int MaxCacheDays => _configuration.GetValue(CachePrefix + "MaxCacheDays", 365);
+ public uint CachedNameLength => _configuration.GetValue(CachePrefix + "CachedNameLength", (uint) 8);
+ public string CacheFolder => _configuration.GetValue(CachePrefix + "Folder", "../App_Data/Cache");
+ public int MaxResizeWidth => _configuration.GetValue(ResizePrefix + "MaxWidth", 5000);
+ public int MaxResizeHeight => _configuration.GetValue(ResizePrefix + "MaxHeight", 5000);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs
new file mode 100644
index 0000000000..b4bb000552
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class IndexCreatorSettings : IIndexCreatorSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Examine:";
+ private readonly IConfiguration _configuration;
+
+ public IndexCreatorSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string LuceneDirectoryFactory =>
+ _configuration.GetValue(Prefix + "LuceneDirectoryFactory");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/KeepAliveSettings.cs b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs
new file mode 100644
index 0000000000..04194e1a3c
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class KeepAliveSettings : IKeepAliveSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "KeepAlive:";
+ private readonly IConfiguration _configuration;
+
+ public KeepAliveSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool DisableKeepAliveTask =>
+ _configuration.GetValue(Prefix + "DisableKeepAliveTask", false);
+
+ public string KeepAlivePingUrl => _configuration.GetValue(Prefix + "KeepAlivePingUrl",
+ "{umbracoApplicationUrl}/api/keepalive/ping");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/LoggingSettings.cs b/src/Umbraco.Configuration/Models/LoggingSettings.cs
new file mode 100644
index 0000000000..b05fe03875
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/LoggingSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class LoggingSettings : ILoggingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Logging:";
+ private readonly IConfiguration _configuration;
+
+ public LoggingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int MaxLogAge => _configuration.GetValue(Prefix + "MaxLogAge", -1);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..c7b147349e
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs
@@ -0,0 +1,38 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class MemberPasswordConfigurationSettings : IMemberPasswordConfiguration
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "MemberPassword:";
+ private readonly IConfiguration _configuration;
+
+ public MemberPasswordConfigurationSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int RequiredLength =>
+ _configuration.GetValue(Prefix + "RequiredLength", 10);
+
+ public bool RequireNonLetterOrDigit =>
+ _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false);
+
+ public bool RequireDigit =>
+ _configuration.GetValue(Prefix + "RequireDigit", false);
+
+ public bool RequireLowercase =>
+ _configuration.GetValue(Prefix + "RequireLowercase", false);
+
+ public bool RequireUppercase =>
+ _configuration.GetValue(Prefix + "RequireUppercase", false);
+
+ public string HashAlgorithmType =>
+ _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256");
+
+ public int MaxFailedAccessAttemptsBeforeLockout =>
+ _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs
new file mode 100644
index 0000000000..d111dbba70
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs
@@ -0,0 +1,86 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ ///
+ /// Represents the models builder configuration.
+ ///
+ internal class ModelsBuilderConfig : IModelsBuilderConfig
+ {
+ private const string Prefix = Constants.Configuration.ConfigModelsBuilderPrefix;
+ private readonly IConfiguration _configuration;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ModelsBuilderConfig(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string DefaultModelsDirectory => "~/App_Data/Models";
+
+ ///
+ /// Gets a value indicating whether the whole models experience is enabled.
+ ///
+ ///
+ /// If this is false then absolutely nothing happens.
+ /// Default value is false which means that unless we have this setting, nothing happens.
+ ///
+ public bool Enable => _configuration.GetValue(Prefix+"Enable", false);
+
+ ///
+ /// Gets the models mode.
+ ///
+ public ModelsMode ModelsMode =>
+ _configuration.GetValue(Prefix+"ModelsMode", ModelsMode.Nothing);
+
+ ///
+ /// Gets the models namespace.
+ ///
+ /// That value could be overriden by other (attribute in user's code...). Return default if no value was supplied.
+ public string ModelsNamespace => _configuration.GetValue(Prefix+"ModelsNamespace");
+
+ ///
+ /// Gets a value indicating whether we should enable the models factory.
+ ///
+ /// Default value is true because no factory is enabled by default in Umbraco.
+ public bool EnableFactory => _configuration.GetValue(Prefix+"EnableFactory", true);
+
+ ///
+ /// Gets a value indicating whether we should flag out-of-date models.
+ ///
+ ///
+ /// Models become out-of-date when data types or content types are updated. When this
+ /// setting is activated the ~/App_Data/Models/ood.txt file is then created. When models are
+ /// generated through the dashboard, the files is cleared. Default value is false.
+ ///
+ public bool FlagOutOfDateModels =>
+ _configuration.GetValue(Prefix+"FlagOutOfDateModels", false) && !ModelsMode.IsLive();
+
+ ///
+ /// Gets the models directory.
+ ///
+ /// Default is ~/App_Data/Models but that can be changed.
+ public string ModelsDirectory =>
+ _configuration.GetValue(Prefix+"ModelsDirectory", "~/App_Data/Models");
+
+ ///
+ /// Gets a value indicating whether to accept an unsafe value for ModelsDirectory.
+ ///
+ ///
+ /// An unsafe value is an absolute path, or a relative path pointing outside
+ /// of the website root.
+ ///
+ public bool AcceptUnsafeModelsDirectory =>
+ _configuration.GetValue(Prefix+"AcceptUnsafeModelsDirectory", false);
+
+ ///
+ /// Gets a value indicating the debug log level.
+ ///
+ /// 0 means minimal (safe on live site), anything else means more and more details (maybe not safe).
+ public int DebugLevel => _configuration.GetValue(Prefix+"DebugLevel", 0);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/NuCacheSettings.cs b/src/Umbraco.Configuration/Models/NuCacheSettings.cs
new file mode 100644
index 0000000000..51b8b1fe08
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/NuCacheSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class NuCacheSettings : INuCacheSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "NuCache:";
+ private readonly IConfiguration _configuration;
+
+ public NuCacheSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string BTreeBlockSize => _configuration.GetValue(Prefix+"BTreeBlockSize");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs
new file mode 100644
index 0000000000..ce5cd65c20
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class RequestHandlerSettings : IRequestHandlerSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "RequestHandler:";
+ private static readonly CharItem[] DefaultCharCollection =
+ {
+ new CharItem { Char = " ", Replacement = "-" },
+ new CharItem { Char = "\"", Replacement = "" },
+ new CharItem { Char = "'", Replacement = "" },
+ new CharItem { Char = "%", Replacement = "" },
+ new CharItem { Char = ".", Replacement = "" },
+ new CharItem { Char = ";", Replacement = "" },
+ new CharItem { Char = "/", Replacement = "" },
+ new CharItem { Char = "\\", Replacement = "" },
+ new CharItem { Char = ":", Replacement = "" },
+ new CharItem { Char = "#", Replacement = "" },
+ new CharItem { Char = "+", Replacement = "plus" },
+ new CharItem { Char = "*", Replacement = "star" },
+ new CharItem { Char = "&", Replacement = "" },
+ new CharItem { Char = "?", Replacement = "" },
+ new CharItem { Char = "æ", Replacement = "ae" },
+ new CharItem { Char = "ä", Replacement = "ae" },
+ new CharItem { Char = "ø", Replacement = "oe" },
+ new CharItem { Char = "ö", Replacement = "oe" },
+ new CharItem { Char = "å", Replacement = "aa" },
+ new CharItem { Char = "ü", Replacement = "ue" },
+ new CharItem { Char = "ß", Replacement = "ss" },
+ new CharItem { Char = "|", Replacement = "-" },
+ new CharItem { Char = "<", Replacement = "" },
+ new CharItem { Char = ">", Replacement = "" }
+ };
+
+ private readonly IConfiguration _configuration;
+
+ public RequestHandlerSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool AddTrailingSlash =>
+ _configuration.GetValue(Prefix+"AddTrailingSlash", true);
+
+ public bool ConvertUrlsToAscii => _configuration
+ .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("true");
+
+ public bool TryConvertUrlsToAscii => _configuration
+ .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("try");
+
+
+ //We need to special handle ":", as this character is special in keys
+ public IEnumerable CharCollection
+ {
+ get
+ {
+ var collection = _configuration.GetSection(Prefix + "CharCollection").GetChildren()
+ .Select(x => new CharItem()
+ {
+ Char = x.GetValue("Char"),
+ Replacement = x.GetValue("Replacement"),
+ }).ToArray();
+
+ if (collection.Any() || _configuration.GetSection("Prefix").GetChildren().Any(x =>
+ x.Key.Equals("CharCollection", StringComparison.OrdinalIgnoreCase)))
+ {
+ return collection;
+ }
+
+ return DefaultCharCollection;
+ }
+ }
+
+
+ public class CharItem : IChar
+ {
+ public string Char { get; set; }
+ public string Replacement { get; set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Configuration/Models/RuntimeSettings.cs
new file mode 100644
index 0000000000..ef129030b6
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/RuntimeSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class RuntimeSettings : IRuntimeSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Runtime:";
+ private readonly IConfiguration _configuration;
+ public RuntimeSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int? MaxQueryStringLength => _configuration.GetValue(Prefix+"MaxRequestLength");
+ public int? MaxRequestLength => _configuration.GetValue(Prefix+"MaxRequestLength");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/SecuritySettings.cs b/src/Umbraco.Configuration/Models/SecuritySettings.cs
new file mode 100644
index 0000000000..9244eace96
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/SecuritySettings.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class SecuritySettings : ISecuritySettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix;
+ private readonly IConfiguration _configuration;
+
+ public SecuritySettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool KeepUserLoggedIn => _configuration.GetValue(Prefix + "KeepUserLoggedIn", true);
+
+ public bool HideDisabledUsersInBackoffice =>
+ _configuration.GetValue(Prefix + "HideDisabledUsersInBackoffice", false);
+
+ public bool AllowPasswordReset =>
+ _configuration.GetValue(Prefix + "AllowPasswordResetAllowPasswordReset", true);
+
+ public string AuthCookieName =>
+ _configuration.GetValue(Prefix + "AuthCookieName", "UMB_UCONTEXT");
+
+ public string AuthCookieDomain =>
+ _configuration.GetValue(Prefix + "AuthCookieDomain");
+
+ public bool UsernameIsEmail => _configuration.GetValue(Prefix + "UsernameIsEmail", true);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/TourSettings.cs b/src/Umbraco.Configuration/Models/TourSettings.cs
new file mode 100644
index 0000000000..9fe1814ff5
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/TourSettings.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class TourSettings : ITourSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Tours:";
+ private readonly IConfiguration _configuration;
+
+ public TourSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string Type { get; set; }
+
+ public bool EnableTours => _configuration.GetValue(Prefix+"EnableTours", true);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/TypeFinderSettings.cs b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs
new file mode 100644
index 0000000000..8a1f7ac9e0
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class TypeFinderSettings : ITypeFinderSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "TypeFinder:";
+ private readonly IConfiguration _configuration;
+
+ public TypeFinderSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string AssembliesAcceptingLoadExceptions =>
+ _configuration.GetValue(Prefix+"AssembliesAcceptingLoadExceptions");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..5e68b16203
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs
@@ -0,0 +1,36 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class UserPasswordConfigurationSettings : IUserPasswordConfiguration
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "UserPassword:";
+ private readonly IConfiguration _configuration;
+
+ public UserPasswordConfigurationSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int RequiredLength => _configuration.GetValue(Prefix + "RequiredLength", 10);
+
+ public bool RequireNonLetterOrDigit =>
+ _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false);
+
+ public bool RequireDigit => _configuration.GetValue(Prefix + "RequireDigit", false);
+
+ public bool RequireLowercase =>
+ _configuration.GetValue(Prefix + "RequireLowercase", false);
+
+ public bool RequireUppercase =>
+ _configuration.GetValue(Prefix + "RequireUppercase", false);
+
+ public string HashAlgorithmType =>
+ _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256");
+
+ public int MaxFailedAccessAttemptsBeforeLockout =>
+ _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs
new file mode 100644
index 0000000000..9ac856ca9f
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Models.PublishedContent;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class WebRoutingSettings : IWebRoutingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "WebRouting:";
+ private readonly IConfiguration _configuration;
+
+ public WebRoutingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool TrySkipIisCustomErrors =>
+ _configuration.GetValue(Prefix + "TrySkipIisCustomErrors", false);
+
+ public bool InternalRedirectPreservesTemplate =>
+ _configuration.GetValue(Prefix + "InternalRedirectPreservesTemplate", false);
+
+ public bool DisableAlternativeTemplates =>
+ _configuration.GetValue(Prefix + "DisableAlternativeTemplates", false);
+
+ public bool ValidateAlternativeTemplates =>
+ _configuration.GetValue(Prefix + "ValidateAlternativeTemplates", false);
+
+ public bool DisableFindContentByIdPath =>
+ _configuration.GetValue(Prefix + "DisableFindContentByIdPath", false);
+
+ public bool DisableRedirectUrlTracking =>
+ _configuration.GetValue(Prefix + "DisableRedirectUrlTracking", false);
+
+ public string UrlProviderMode =>
+ _configuration.GetValue(Prefix + "UrlProviderMode", UrlMode.Auto.ToString());
+
+ public string UmbracoApplicationUrl =>
+ _configuration.GetValue(Prefix + "UmbracoApplicationUrl");
+ }
+}
diff --git a/src/Umbraco.Configuration/Umbraco.Configuration.csproj b/src/Umbraco.Configuration/Umbraco.Configuration.csproj
index 57fca1dfd6..88bb3639d0 100644
--- a/src/Umbraco.Configuration/Umbraco.Configuration.csproj
+++ b/src/Umbraco.Configuration/Umbraco.Configuration.csproj
@@ -22,6 +22,9 @@
+
+
+
diff --git a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs b/src/Umbraco.Configuration/UmbracoVersionExtensions.cs
deleted file mode 100644
index 168bb16f57..0000000000
--- a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Configuration;
-using Semver;
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-
-namespace Umbraco.Configuration
-{
- public static class UmbracoVersionExtensions
- {
- ///
- /// Gets the "local" version of the site.
- ///
- ///
- /// Three things have a version, really: the executing code, the database model,
- /// and the site/files. The database model version is entirely managed via migrations,
- /// and changes during an upgrade. The executing code version changes when new code is
- /// deployed. The site/files version changes during an upgrade.
- ///
- public static SemVersion LocalVersion(this IUmbracoVersion umbracoVersion)
- {
- try
- {
- // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
- var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus];
- return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
- }
- catch
- {
- return null;
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
index 452f897372..e70b40160e 100644
--- a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
+++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
@@ -73,7 +73,7 @@ namespace Umbraco.Core.Cache
var result = SafeLazy.GetSafeLazy(factory);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
// do not store null values (backward compat), clone / reset to go into the cache
- return value == null ? null : CheckCloneableAndTracksChanges(value);
+ return value == null ? null : CheckCloneableAndTracksChanges(value);
// clone / reset to go into the cache
}, timeout, isSliding, dependentFiles);
@@ -107,9 +107,9 @@ namespace Umbraco.Core.Cache
}
///
- public void ClearOfType(string typeName)
+ public void ClearOfType(Type type)
{
- InnerCache.ClearOfType(typeName);
+ InnerCache.ClearOfType(type);
}
///
diff --git a/src/Umbraco.Core/Cache/DictionaryAppCache.cs b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
index d372916240..04ee3e0afa 100644
--- a/src/Umbraco.Core/Cache/DictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
@@ -71,16 +71,16 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType().ToString().InvariantEquals(typeName));
+ _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == type);
}
///
public virtual void ClearOfType()
{
var typeOfT = typeof(T);
- _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT);
+ ClearOfType(typeOfT);
}
///
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
index 159f9cd7cb..54009af465 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
@@ -12,12 +12,6 @@ namespace Umbraco.Core.Cache
///
public class FastDictionaryAppCache : IAppCache
{
- private readonly ITypeFinder _typeFinder;
-
- public FastDictionaryAppCache(ITypeFinder typeFinder)
- {
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- }
///
/// Gets the internal items dictionary, for tests only!
@@ -83,9 +77,8 @@ namespace Umbraco.Core.Cache
}
///
- public void ClearOfType(string typeName)
+ public void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
index f417c5ffd0..bb55762826 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
@@ -12,13 +12,6 @@ namespace Umbraco.Core.Cache
///
public abstract class FastDictionaryAppCacheBase : IAppCache
{
- private readonly ITypeFinder _typeFinder;
-
- protected FastDictionaryAppCacheBase(ITypeFinder typeFinder)
- {
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- }
-
// prefix cache keys so we know which one are ours
protected const string CacheItemPrefix = "umbrtmche";
@@ -121,9 +114,8 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
index e698d93ebe..6ce43a7bc9 100644
--- a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
+++ b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache
///
/// Initializes a new instance of the class with a context, for unit tests!
///
- public HttpRequestAppCache(Func requestItems, ITypeFinder typeFinder) : base(typeFinder)
+ public HttpRequestAppCache(Func requestItems) : base()
{
ContextItems = requestItems;
}
diff --git a/src/Umbraco.Core/Cache/IAppCache.cs b/src/Umbraco.Core/Cache/IAppCache.cs
index 674781f6d6..c84ec1135c 100644
--- a/src/Umbraco.Core/Cache/IAppCache.cs
+++ b/src/Umbraco.Core/Cache/IAppCache.cs
@@ -51,14 +51,14 @@ namespace Umbraco.Core.Cache
///
/// Removes items of a specified type from the cache.
///
- /// The name of the type to remove.
+ /// The type to remove.
///
/// If the type is an interface, then all items of a type implementing that interface are
/// removed. Otherwise, only items of that exact type are removed (items of type inheriting from
/// the specified type are not removed).
/// Performs a case-sensitive search.
///
- void ClearOfType(string typeName);
+ void ClearOfType(Type type);
///
/// Removes items of a specified type from the cache.
diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs
index 60bc6fb8b8..cae3a7381e 100644
--- a/src/Umbraco.Core/Cache/NoAppCache.cs
+++ b/src/Umbraco.Core/Cache/NoAppCache.cs
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Cache
{ }
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{ }
///
diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
index 208390276a..dc9163affb 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
@@ -13,15 +13,13 @@ namespace Umbraco.Core.Cache
///
public class ObjectCacheAppCache : IAppPolicyCache
{
- private readonly ITypeFinder _typeFinder;
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
///
/// Initializes a new instance of the .
///
- public ObjectCacheAppCache(ITypeFinder typeFinder)
+ public ObjectCacheAppCache()
{
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
// the MemoryCache is created with name "in-memory". That name is
// used to retrieve configuration options. It does not identify the memory cache, i.e.
// each instance of this class has its own, independent, memory cache.
@@ -178,9 +176,8 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs
index a186a1f00a..9a696c2dc0 100644
--- a/src/Umbraco.Core/Composing/Composition.cs
+++ b/src/Umbraco.Core/Composing/Composition.cs
@@ -135,7 +135,7 @@ namespace Umbraco.Core.Composing
IFactory factory = null;
- Configs.RegisterWith(_register, () => factory);
+ Configs.RegisterWith(_register);
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
diff --git a/src/Umbraco.Core/Configuration/Configs.cs b/src/Umbraco.Core/Configuration/Configs.cs
index abb06d525f..821ee308f0 100644
--- a/src/Umbraco.Core/Configuration/Configs.cs
+++ b/src/Umbraco.Core/Configuration/Configs.cs
@@ -13,16 +13,8 @@ namespace Umbraco.Core.Configuration
///
public class Configs
{
- private readonly Func _configSectionResolver;
-
- public Configs(Func configSectionResolver)
- {
- _configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver));
- }
-
private readonly Dictionary> _configs = new Dictionary>();
private Dictionary> _registerings = new Dictionary>();
- private Lazy _factory;
///
/// Gets a configuration.
@@ -52,61 +44,15 @@ namespace Umbraco.Core.Configuration
_registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton);
}
- ///
- /// Adds a configuration, provided by a factory.
- ///
- public void Add(Func configFactory)
- where TConfig : class
- {
- // make sure it is not too late
- if (_registerings == null)
- throw new InvalidOperationException("Configurations have already been registered.");
-
- var typeOfConfig = typeof(TConfig);
-
- _configs[typeOfConfig] = new Lazy
public static class ConfigsExtensions
{
+
+ public static IImagingSettings Imaging(this Configs configs)
+ => configs.GetConfig();
public static IGlobalSettings Global(this Configs configs)
=> configs.GetConfig();
@@ -43,26 +40,10 @@ namespace Umbraco.Core
public static IWebRoutingSettings WebRouting(this Configs configs)
=> configs.GetConfig();
- public static IHealthChecks HealthChecks(this Configs configs)
- => configs.GetConfig();
+ public static IHealthChecksSettings HealthChecks(this Configs configs)
+ => configs.GetConfig();
+ public static ICoreDebugSettings CoreDebug(this Configs configs)
+ => configs.GetConfig();
- public static IGridConfig Grids(this Configs configs)
- => configs.GetConfig();
-
- public static ICoreDebug CoreDebug(this Configs configs)
- => configs.GetConfig();
-
- public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper)
- {
- var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config));
-
- // GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition
- configs.Add(factory => new GridConfig(
- factory.GetInstance(),
- factory.GetInstance(),
- configDir,
- factory.GetInstance(),
- factory.GetInstance().Debug));
- }
}
}
diff --git a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs
deleted file mode 100644
index 4d8039dfbb..0000000000
--- a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using Umbraco.Core.IO;
-
-namespace Umbraco.Core.Configuration
-{
- public static class GlobalSettingsExtensions
- {
- private static string _mvcArea;
-
-
- ///
- /// This returns the string of the MVC Area route.
- ///
- ///
- /// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
- /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
- /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
- ///
- /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
- /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
- ///
- public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IIOHelper ioHelper)
- {
- if (_mvcArea != null) return _mvcArea;
-
- _mvcArea = GetUmbracoMvcAreaNoCache(globalSettings, ioHelper);
-
- return _mvcArea;
- }
-
- internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IIOHelper ioHelper)
- {
- if (globalSettings.Path.IsNullOrWhiteSpace())
- {
- throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
- }
-
- var path = globalSettings.Path;
- if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518
- path = path.Substring(ioHelper.Root.Length);
- return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
- }
-
- }
-}
diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
index de4f7ccd5a..72c720e3d6 100644
--- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
+++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
@@ -1,15 +1,18 @@
using System.IO;
using Umbraco.Core.Cache;
+using Umbraco.Core.Hosting;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
+using Umbraco.Core.Serialization;
namespace Umbraco.Core.Configuration.Grid
{
public class GridConfig : IGridConfig
{
- public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
+ public GridConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment)
{
- EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug);
+ EditorsConfig = new GridEditorsConfig(appCaches, ioHelper, manifestParser, jsonSerializer, hostingEnvironment.IsDebugMode);
}
public IGridEditorsConfig EditorsConfig { get; }
diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
index a1ebf008fc..410c83ff1a 100644
--- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
+++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
@@ -1,27 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
+using Umbraco.Composing;
using Umbraco.Core.Cache;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.Serialization;
namespace Umbraco.Core.Configuration.Grid
{
internal class GridEditorsConfig : IGridEditorsConfig
{
- private readonly ILogger _logger;
private readonly AppCaches _appCaches;
- private readonly DirectoryInfo _configFolder;
+ private readonly IIOHelper _ioHelper;
private readonly IManifestParser _manifestParser;
private readonly bool _isDebug;
+ private readonly IJsonSerializer _jsonSerializer;
- public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
+ public GridEditorsConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser,IJsonSerializer jsonSerializer, bool isDebug)
{
- _logger = logger;
_appCaches = appCaches;
- _configFolder = configFolder;
+ _ioHelper = ioHelper;
_manifestParser = manifestParser;
+ _jsonSerializer = jsonSerializer;
_isDebug = isDebug;
}
@@ -31,19 +34,20 @@ namespace Umbraco.Core.Configuration.Grid
{
List GetResult()
{
+ var configFolder = new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.Config));
var editors = new List();
- var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
+ var gridConfig = Path.Combine(configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
var sourceString = File.ReadAllText(gridConfig);
try
{
- editors.AddRange(_manifestParser.ParseGridEditors(sourceString));
+ editors.AddRange(_jsonSerializer.Deserialize>(sourceString));
}
catch (Exception ex)
{
- _logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
+ Current.Logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
}
}
@@ -63,7 +67,6 @@ namespace Umbraco.Core.Configuration.Grid
return result;
}
-
}
}
}
diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
similarity index 84%
rename from src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs
rename to src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
index fa98e3b054..785e8d5651 100644
--- a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs
+++ b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
- public interface IHealthChecks
+ public interface IHealthChecksSettings
{
IEnumerable DisabledChecks { get; }
IHealthCheckNotificationSettings NotificationSettings { get; }
diff --git a/src/Umbraco.Core/Configuration/IConfigManipulator.cs b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
new file mode 100644
index 0000000000..83ab2c0631
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
@@ -0,0 +1,10 @@
+using Umbraco.Core.IO;
+
+namespace Umbraco.Core.Configuration
+{
+ public interface IConfigManipulator
+ {
+ void RemoveConnectionString();
+ void SaveConnectionString(string connectionString, string providerName);
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IConfigsFactory.cs b/src/Umbraco.Core/Configuration/IConfigsFactory.cs
index b2ad6295a1..dd2459b88c 100644
--- a/src/Umbraco.Core/Configuration/IConfigsFactory.cs
+++ b/src/Umbraco.Core/Configuration/IConfigsFactory.cs
@@ -5,6 +5,6 @@ namespace Umbraco.Core.Configuration
{
public interface IConfigsFactory
{
- Configs Create(IIOHelper ioHelper, ILogger logger);
+ Configs Create();
}
}
diff --git a/src/Umbraco.Core/Configuration/IConnectionStrings.cs b/src/Umbraco.Core/Configuration/IConnectionStrings.cs
index 2a14c0e614..0d33378669 100644
--- a/src/Umbraco.Core/Configuration/IConnectionStrings.cs
+++ b/src/Umbraco.Core/Configuration/IConnectionStrings.cs
@@ -6,8 +6,5 @@ namespace Umbraco.Core.Configuration
{
get;
}
-
- void RemoveConnectionString(string umbracoConnectionName);
- void SaveConnectionString(string connectionString, string providerName);
}
}
diff --git a/src/Umbraco.Core/Configuration/ICoreDebug.cs b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
similarity index 93%
rename from src/Umbraco.Core/Configuration/ICoreDebug.cs
rename to src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
index 4ff2a1a300..586e4bc3e4 100644
--- a/src/Umbraco.Core/Configuration/ICoreDebug.cs
+++ b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration
{
- public interface ICoreDebug
+ public interface ICoreDebugSettings
{
///
/// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed.
diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
index fa96f66d00..3cb211a7a7 100644
--- a/src/Umbraco.Core/Configuration/IGlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
@@ -21,7 +21,7 @@
string ReservedPaths { get; }
///
- /// Gets the path to umbraco's root directory (/umbraco by default).
+ /// Gets the path to umbraco's root directory.
///
string Path { get; }
diff --git a/src/Umbraco.Core/Configuration/IImagingSettings.cs b/src/Umbraco.Core/Configuration/IImagingSettings.cs
new file mode 100644
index 0000000000..13e1b30389
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IImagingSettings.cs
@@ -0,0 +1,12 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IImagingSettings
+ {
+ int MaxBrowserCacheDays { get;}
+ int MaxCacheDays { get; }
+ uint CachedNameLength { get; }
+ int MaxResizeWidth { get; }
+ int MaxResizeHeight { get; }
+ string CacheFolder { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs b/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs
deleted file mode 100644
index 35969e668a..0000000000
--- a/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Umbraco.Core.Configuration
-{
- public interface IMachineKeyConfig
- {
- bool HasMachineKey { get;}
- }
-}
diff --git a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
index 6a071ac277..990bde9843 100644
--- a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
+++ b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
@@ -7,7 +7,6 @@
int DebugLevel { get; }
bool EnableFactory { get; }
bool FlagOutOfDateModels { get; }
- bool IsDebug { get; }
string ModelsDirectory { get; }
ModelsMode ModelsMode { get; }
string ModelsNamespace { get; }
diff --git a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
index 98cd1010c0..6a5fd8e73f 100644
--- a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
@@ -6,13 +6,11 @@
///
public interface IPasswordConfiguration
{
- int RequiredLength { get; }
+ int RequiredLength { get; }
bool RequireNonLetterOrDigit { get; }
bool RequireDigit { get; }
bool RequireLowercase { get; }
bool RequireUppercase { get; }
-
- bool UseLegacyEncoding { get; }
string HashAlgorithmType { get; }
// TODO: This doesn't really belong here
diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs
new file mode 100644
index 0000000000..3e3b116395
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs
@@ -0,0 +1,57 @@
+using System.Configuration;
+using System.IO;
+using Umbraco.Core.IO;
+
+namespace Umbraco.Core.Configuration
+{
+ public static class ModelsBuilderConfigExtensions
+ {
+ private static string _modelsDirectoryAbsolute = null;
+
+ public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IIOHelper ioHelper)
+ {
+
+ if (_modelsDirectoryAbsolute is null)
+ {
+ var modelsDirectory = modelsBuilderConfig.ModelsDirectory;
+ var root = ioHelper.MapPath("~/");
+
+ _modelsDirectoryAbsolute = GetModelsDirectory(root, modelsDirectory,
+ modelsBuilderConfig.AcceptUnsafeModelsDirectory);
+ }
+
+ return _modelsDirectoryAbsolute;
+ }
+
+ // internal for tests
+ internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe)
+ {
+ // making sure it is safe, ie under the website root,
+ // unless AcceptUnsafeModelsDirectory and then everything is OK.
+
+ if (!Path.IsPathRooted(root))
+ throw new ConfigurationErrorsException($"Root is not rooted \"{root}\".");
+
+ if (config.StartsWith("~/"))
+ {
+ var dir = Path.Combine(root, config.TrimStart("~/"));
+
+ // sanitize - GetFullPath will take care of any relative
+ // segments in path, eg '../../foo.tmp' - it may throw a SecurityException
+ // if the combined path reaches illegal parts of the filesystem
+ dir = Path.GetFullPath(dir);
+ root = Path.GetFullPath(root);
+
+ if (!dir.StartsWith(root) && !acceptUnsafe)
+ throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
+
+ return dir;
+ }
+
+ if (acceptUnsafe)
+ return Path.GetFullPath(config);
+
+ throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
index 6827695b35..0c5ed9adb0 100644
--- a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
@@ -17,7 +17,6 @@ namespace Umbraco.Core.Configuration
RequireDigit = configSettings.RequireDigit;
RequireLowercase = configSettings.RequireLowercase;
RequireUppercase = configSettings.RequireUppercase;
- UseLegacyEncoding = configSettings.UseLegacyEncoding;
HashAlgorithmType = configSettings.HashAlgorithmType;
MaxFailedAccessAttemptsBeforeLockout = configSettings.MaxFailedAccessAttemptsBeforeLockout;
}
@@ -32,8 +31,6 @@ namespace Umbraco.Core.Configuration
public bool RequireUppercase { get; }
- public bool UseLegacyEncoding { get; }
-
public string HashAlgorithmType { get; }
public int MaxFailedAccessAttemptsBeforeLockout { get; }
diff --git a/src/Umbraco.Configuration/ConnectionStrings.cs b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
similarity index 65%
rename from src/Umbraco.Configuration/ConnectionStrings.cs
rename to src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
index 23436d6caf..333f9dc6f9 100644
--- a/src/Umbraco.Configuration/ConnectionStrings.cs
+++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
@@ -3,34 +3,26 @@ using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
+using Umbraco.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
- public class ConnectionStrings : IConnectionStrings
+ public class XmlConfigManipulator : IConfigManipulator
{
private readonly IIOHelper _ioHelper;
private readonly ILogger _logger;
- public ConnectionStrings(IIOHelper ioHelper, ILogger logger)
+ public XmlConfigManipulator(IIOHelper ioHelper, ILogger logger)
{
_ioHelper = ioHelper;
_logger = logger;
}
- public ConfigConnectionString this[string key]
- {
- get
- {
- var settings = ConfigurationManager.ConnectionStrings[key];
- if (settings == null) return null;
- return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name);
- }
- }
-
- public void RemoveConnectionString(string key)
+ public void RemoveConnectionString()
{
+ var key = Constants.System.UmbracoConnectionName;
var fileName = _ioHelper.MapPath(string.Format("{0}/web.config", _ioHelper.Root));
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
@@ -43,26 +35,30 @@ namespace Umbraco.Core.Configuration
xml.Save(fileName, SaveOptions.DisableFormatting);
ConfigurationManager.RefreshSection("appSettings");
}
+
var settings = ConfigurationManager.ConnectionStrings[key];
}
- ///
- /// Saves the connection string as a proper .net connection string in web.config.
+ ///
+ /// Saves the connection string as a proper .net connection string in web.config.
///
/// Saves the ConnectionString in the very nasty 'medium trust'-supportive way.
/// The connection string.
/// The provider name.
- public void SaveConnectionString(string connectionString, string providerName)
+ public void SaveConnectionString(string connectionString, string providerName)
{
-
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));
- if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionString));
+ if (string.IsNullOrWhiteSpace(connectionString))
+ throw new ArgumentException("Value can't be empty or consist only of white-space characters.",
+ nameof(connectionString));
if (providerName == null) throw new ArgumentNullException(nameof(providerName));
- if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(providerName));
+ if (string.IsNullOrWhiteSpace(providerName))
+ throw new ArgumentException("Value can't be empty or consist only of white-space characters.",
+ nameof(providerName));
var fileSource = "web.config";
- var fileName = _ioHelper.MapPath(_ioHelper.Root +"/" + fileSource);
+ var fileName = _ioHelper.MapPath(_ioHelper.Root + "/" + fileSource);
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
@@ -84,11 +80,13 @@ namespace Umbraco.Core.Configuration
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
- if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings).");
+ if (connectionStrings == null)
+ throw new Exception($"Invalid {fileSource} file (no connection strings).");
}
// create or update connection string
- var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName);
+ var setting = connectionStrings.Descendants("add").FirstOrDefault(s =>
+ s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName);
if (setting == null)
{
connectionStrings.Add(new XElement("add",
@@ -103,19 +101,18 @@ namespace Umbraco.Core.Configuration
}
// save
- _logger.Info("Saving connection string to {ConfigFile}.", fileSource);
+ _logger.Info("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
- _logger.Info("Saved connection string to {ConfigFile}.", fileSource);
+ _logger.Info("Saved connection string to {ConfigFile}.", fileSource);
}
- private static void AddOrUpdateAttribute(XElement element, string name, string value)
- {
- var attribute = element.Attribute(name);
- if (attribute == null)
- element.Add(new XAttribute(name, value));
- else
- attribute.Value = value;
- }
-
+ private static void AddOrUpdateAttribute(XElement element, string name, string value)
+ {
+ var attribute = element.Attribute(name);
+ if (attribute == null)
+ element.Add(new XAttribute(name, value));
+ else
+ attribute.Value = value;
+ }
}
}
diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs
new file mode 100644
index 0000000000..c45229d918
--- /dev/null
+++ b/src/Umbraco.Core/Constants-Configuration.cs
@@ -0,0 +1,18 @@
+namespace Umbraco.Core
+{
+ public static partial class Constants
+ {
+ public static class Configuration
+ {
+ ///
+ /// Case insensitive prefix for all configurations
+ ///
+ ///
+ /// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}}
+ ///
+ public const string ConfigPrefix = "Umbraco:CMS:";
+ public const string ConfigSecurityPrefix = ConfigPrefix+"Security:";
+ public const string ConfigModelsBuilderPrefix = ConfigPrefix+"ModelsBuilder:";
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs
index abb92298f4..837db01b63 100644
--- a/src/Umbraco.Core/Constants-System.cs
+++ b/src/Umbraco.Core/Constants-System.cs
@@ -1,4 +1,4 @@
-namespace Umbraco.Core
+ namespace Umbraco.Core
{
public static partial class Constants
{
diff --git a/src/Umbraco.Core/IO/IIOHelper.cs b/src/Umbraco.Core/IO/IIOHelper.cs
index 11f5c6c565..f478b49de6 100644
--- a/src/Umbraco.Core/IO/IIOHelper.cs
+++ b/src/Umbraco.Core/IO/IIOHelper.cs
@@ -4,6 +4,9 @@ namespace Umbraco.Core.IO
{
public interface IIOHelper
{
+
+ string BackOfficePath { get; }
+
bool ForceNotHosted { get; set; }
char DirSepChar { get; }
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
index d5e1335f35..3abd413fd4 100644
--- a/src/Umbraco.Core/IO/IOHelper.cs
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.Reflection;
using System.IO;
using System.Linq;
+using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Strings;
@@ -12,10 +13,22 @@ namespace Umbraco.Core.IO
public class IOHelper : IIOHelper
{
private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IGlobalSettings _globalSettings;
- public IOHelper(IHostingEnvironment hostingEnvironment)
+ public IOHelper(IHostingEnvironment hostingEnvironment, IGlobalSettings globalSettings)
{
_hostingEnvironment = hostingEnvironment;
+ _globalSettings = globalSettings;
+ }
+
+ public string BackOfficePath
+ {
+ get
+ {
+ var path = _globalSettings.Path;
+
+ return string.IsNullOrEmpty(path) ? string.Empty : ResolveUrl(path);
+ }
}
///
diff --git a/src/Umbraco.Core/IO/IOHelperExtensions.cs b/src/Umbraco.Core/IO/IOHelperExtensions.cs
index 64b57e7dc1..39bd5e6cc9 100644
--- a/src/Umbraco.Core/IO/IOHelperExtensions.cs
+++ b/src/Umbraco.Core/IO/IOHelperExtensions.cs
@@ -5,6 +5,8 @@ namespace Umbraco.Core.IO
{
public static class IOHelperExtensions
{
+ private static string _mvcArea;
+
///
/// Tries to create a directory.
///
@@ -35,5 +37,38 @@ namespace Umbraco.Core.IO
{
return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8);
}
+
+ ///
+ /// This returns the string of the MVC Area route.
+ ///
+ ///
+ /// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
+ /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
+ /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
+ ///
+ /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
+ /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
+ ///
+ public static string GetUmbracoMvcArea(this IIOHelper ioHelper)
+ {
+ if (_mvcArea != null) return _mvcArea;
+
+ _mvcArea = GetUmbracoMvcAreaNoCache(ioHelper);
+
+ return _mvcArea;
+ }
+
+ internal static string GetUmbracoMvcAreaNoCache(this IIOHelper ioHelper)
+ {
+ if (ioHelper.BackOfficePath.IsNullOrWhiteSpace())
+ {
+ throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
+ }
+
+ var path = ioHelper.BackOfficePath;
+ if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518
+ path = path.Substring(ioHelper.Root.Length);
+ return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
+ }
}
}
diff --git a/src/Umbraco.Core/Manifest/IManifestParser.cs b/src/Umbraco.Core/Manifest/IManifestParser.cs
index eeb0c756f6..3eec7007b3 100644
--- a/src/Umbraco.Core/Manifest/IManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/IManifestParser.cs
@@ -17,7 +17,5 @@ namespace Umbraco.Core.Manifest
/// Parses a manifest.
///
PackageManifest ParseManifest(string text);
-
- IEnumerable ParseGridEditors(string text);
}
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 7a15e7fbed..c083cccf8f 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs
index cf84d7914d..4321aefd7f 100644
--- a/src/Umbraco.Core/UriExtensions.cs
+++ b/src/Umbraco.Core/UriExtensions.cs
@@ -40,7 +40,7 @@ namespace Umbraco.Core
/// But if we've got this far we'll just have to assume it's front-end anyways.
///
///
- internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IGlobalSettings globalSettings, IIOHelper ioHelper)
+ internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IIOHelper ioHelper)
{
applicationPath = applicationPath ?? string.Empty;
@@ -49,11 +49,11 @@ namespace Umbraco.Core
var urlPath = fullUrlPath.TrimStart(appPath).EnsureStartsWith('/');
//check if this is in the umbraco back office
- var isUmbracoPath = urlPath.InvariantStartsWith(globalSettings.Path.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/'));
+ var isUmbracoPath = urlPath.InvariantStartsWith(ioHelper.BackOfficePath.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/'));
//if not, then def not back office
if (isUmbracoPath == false) return false;
- var mvcArea = globalSettings.GetUmbracoMvcArea(ioHelper);
+ var mvcArea = ioHelper.GetUmbracoMvcArea();
//if its the normal /umbraco path
if (urlPath.InvariantEquals("/" + mvcArea)
|| urlPath.InvariantEquals("/" + mvcArea + "/"))
@@ -127,12 +127,12 @@ namespace Umbraco.Core
///
///
///
- internal static bool IsDefaultBackOfficeRequest(this Uri url, IGlobalSettings globalSettings)
+ internal static bool IsDefaultBackOfficeRequest(this Uri url, IIOHelper ioHelper)
{
- if (url.AbsolutePath.InvariantEquals(globalSettings.Path.TrimEnd("/"))
- || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/'))
- || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default")
- || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default/"))
+ if (url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.TrimEnd("/"))
+ || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/'))
+ || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/') + "Default")
+ || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/') + "Default/"))
{
return true;
}
diff --git a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs
new file mode 100644
index 0000000000..3c78faea37
--- /dev/null
+++ b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json.Serialization;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration.Json;
+using Microsoft.Extensions.FileProviders;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Umbraco.Core.IO;
+using Umbraco.Core.Serialization;
+
+namespace Umbraco.Core.Configuration
+{
+ public class JsonConfigManipulator : IConfigManipulator
+ {
+ private readonly IConfiguration _configuration;
+
+ public JsonConfigManipulator(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string UmbracoConnectionPath { get; } = $"ConnectionStrings:{ Constants.System.UmbracoConnectionName}";
+ public void RemoveConnectionString()
+ {
+ var provider = GetJsonConfigurationProvider(UmbracoConnectionPath);
+
+ var json = GetJson(provider);
+
+ RemoveJsonKey(json, UmbracoConnectionPath);
+
+ SaveJson(provider, json);
+ }
+
+ public void SaveConnectionString(string connectionString, string providerName)
+ {
+ var provider = GetJsonConfigurationProvider();
+
+ var json = GetJson(provider);
+
+ var item = GetConnectionItem(connectionString, providerName);
+
+ json.Merge(item, new JsonMergeSettings());
+
+ SaveJson(provider, json);
+ }
+
+
+ private JToken GetConnectionItem(string connectionString, string providerName)
+ {
+ JTokenWriter writer = new JTokenWriter();
+
+ writer.WriteStartObject();
+ writer.WritePropertyName("ConnectionStrings");
+ writer.WriteStartObject();
+ writer.WritePropertyName(Constants.System.UmbracoConnectionName);
+ writer.WriteValue(connectionString);
+ writer.WriteEndObject();
+ writer.WriteEndObject();
+
+ return writer.Token;
+ }
+
+ private static void RemoveJsonKey(JObject json, string key)
+ {
+ JToken token = json;
+ foreach (var propertyName in key.Split(new[] { ':' }))
+ {
+ token = CaseSelectPropertyValues(token, propertyName);
+ }
+
+ token?.Parent?.Remove();
+ }
+
+ private static void SaveJson(JsonConfigurationProvider provider, JObject json)
+ {
+ if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider)
+ {
+ var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path);
+
+ using (var sw = new StreamWriter(jsonFilePath, false))
+ using (var jsonTextWriter = new JsonTextWriter(sw)
+ {
+ Formatting = Formatting.Indented,
+ })
+ {
+ json?.WriteTo(jsonTextWriter);
+ }
+ }
+
+ }
+
+ private static JObject GetJson(JsonConfigurationProvider provider)
+ {
+ if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider)
+ {
+ var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path);
+
+ var serializer = new JsonSerializer();
+ using (var sr = new StreamReader(jsonFilePath))
+ using (var jsonTextReader = new JsonTextReader(sr))
+ {
+ return serializer.Deserialize(jsonTextReader);
+ }
+ }
+
+ return null;
+ }
+
+
+
+
+ private JsonConfigurationProvider GetJsonConfigurationProvider(string requiredKey = null)
+ {
+ if (_configuration is IConfigurationRoot configurationRoot)
+ {
+ foreach (var provider in configurationRoot.Providers)
+ {
+ if(provider is JsonConfigurationProvider jsonConfigurationProvider)
+ {
+ if (requiredKey is null || provider.TryGet(requiredKey, out _))
+ {
+ return jsonConfigurationProvider;
+ }
+ }
+ }
+ }
+ throw new InvalidOperationException("Could not find a writable json config source");
+ }
+
+ ///
+ /// Returns the property value when case insensative
+ ///
+ ///
+ /// This method is required because keys are case insensative in IConfiguration.
+ /// JObject[..] do not support case insensative and JObject.Property(...) do not return a new JObject.
+ ///
+ private static JToken CaseSelectPropertyValues(JToken token, string name)
+ {
+ if (token is JObject obj)
+ {
+
+ foreach (var property in obj.Properties())
+ {
+ if (name is null)
+ return property.Value;
+ if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase))
+ return property.Value;
+ }
+ }
+ return null;
+ }
+
+ }
+}
diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
index f76a69c0fa..9d36b60d83 100644
--- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
+++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
private readonly IGlobalSettings _globalSettings;
private readonly IContentSettings _contentSettings;
- public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecks healthChecks, IContentSettings contentSettings) : base(healthChecks)
+ public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecksSettings healthChecksSettings, IContentSettings contentSettings) : base(healthChecksSettings)
{
var recipientEmail = Settings["recipientEmail"]?.Value;
if (string.IsNullOrWhiteSpace(recipientEmail))
diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs
index ff6fbe2371..9c3516e712 100644
--- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs
+++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs
@@ -8,7 +8,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
{
public abstract class NotificationMethodBase : IHealthCheckNotificationMethod
{
- protected NotificationMethodBase(IHealthChecks healthCheckConfig)
+ protected NotificationMethodBase(IHealthChecksSettings healthCheckSettingsConfig)
{
var type = GetType();
var attribute = type.GetCustomAttribute();
@@ -18,7 +18,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
return;
}
- var notificationMethods = healthCheckConfig.NotificationSettings.NotificationMethods;
+ var notificationMethods = healthCheckSettingsConfig.NotificationSettings.NotificationMethods;
var notificationMethod = notificationMethods[attribute.Alias];
if (notificationMethod == null)
{
diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs
deleted file mode 100644
index fb8201600c..0000000000
--- a/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System.Linq;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.IO;
-using Umbraco.Core.Security;
-using Umbraco.Web.Install.Models;
-
-namespace Umbraco.Web.Install.InstallSteps
-{
- [InstallSetupStep(InstallationType.NewInstall,
- "ConfigureMachineKey", "machinekey", 2,
- "Updating some security settings...",
- PerformsAppRestart = true)]
- public class ConfigureMachineKey : InstallSetupStep
- {
- private readonly IIOHelper _ioHelper;
- private readonly IMachineKeyConfig _machineKeyConfig;
-
- public ConfigureMachineKey(IIOHelper ioHelper, IMachineKeyConfig machineKeyConfig)
- {
- _ioHelper = ioHelper;
- _machineKeyConfig = machineKeyConfig;
- }
-
- public override string View => HasMachineKey() == false ? base.View : "";
-
- ///
- /// Don't display the view or execute if a machine key already exists
- ///
- ///
- private bool HasMachineKey()
- {
- return _machineKeyConfig.HasMachineKey;
- }
-
- ///
- /// The step execution method
- ///
- ///
- ///
- public override Task ExecuteAsync(bool? model)
- {
- if (model.HasValue && model.Value == false) return Task.FromResult(null);
-
- //install the machine key
- var fileName = _ioHelper.MapPath($"{_ioHelper.Root}/web.config");
- var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
-
- // we only want to get the element that is under the root, (there may be more under tags we don't want them)
- var systemWeb = xml.Root.Element("system.web");
-
- // Update appSetting if it exists, or else create a new appSetting for the given key and value
- var machineKey = systemWeb.Descendants("machineKey").FirstOrDefault();
- if (machineKey != null) return Task.FromResult(null);
-
- var generator = new MachineKeyGenerator();
- var generatedSection = generator.GenerateConfigurationBlock();
- systemWeb.Add(XElement.Parse(generatedSection));
-
- xml.Save(fileName, SaveOptions.DisableFormatting);
-
- return Task.FromResult(null);
- }
-
- public override bool RequiresExecution(bool? model)
- {
- return HasMachineKey() == false;
- }
- }
-}
diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs
index a7b3dcc218..865df4bc02 100644
--- a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs
+++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs
@@ -19,14 +19,16 @@ namespace Umbraco.Web.Install.InstallSteps
private readonly ILogger _logger;
private readonly IIOHelper _ioHelper;
private readonly IConnectionStrings _connectionStrings;
+ private readonly IConfigManipulator _configManipulator;
- public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings)
+ public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings, IConfigManipulator configManipulator)
{
_databaseBuilder = databaseBuilder;
_runtime = runtime;
_logger = logger;
_ioHelper = ioHelper;
_connectionStrings = connectionStrings;
+ _configManipulator = configManipulator;
}
public override Task ExecuteAsync(object model)
@@ -43,7 +45,7 @@ namespace Umbraco.Web.Install.InstallSteps
if (result.RequiresUpgrade == false)
{
- HandleConnectionStrings(_logger, _ioHelper, _connectionStrings);
+ HandleConnectionStrings(_logger, _ioHelper, _connectionStrings, _configManipulator);
return Task.FromResult(null);
}
@@ -54,7 +56,7 @@ namespace Umbraco.Web.Install.InstallSteps
}));
}
- internal static void HandleConnectionStrings(ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings)
+ internal static void HandleConnectionStrings(ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings, IConfigManipulator configManipulator)
{
@@ -65,7 +67,7 @@ namespace Umbraco.Web.Install.InstallSteps
// Remove legacy umbracoDbDsn configuration setting if it exists and connectionstring also exists
if (databaseSettings != null)
{
- connectionStrings.RemoveConnectionString(Constants.System.UmbracoConnectionName);
+ configManipulator.RemoveConnectionString();
}
else
{
diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs
index 3cd3c1ca56..91a718d0f4 100644
--- a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs
+++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs
@@ -23,8 +23,17 @@ namespace Umbraco.Web.Install.InstallSteps
private readonly IGlobalSettings _globalSettings;
private readonly IConnectionStrings _connectionStrings;
private readonly IIOHelper _ioHelper;
+ private readonly IConfigManipulator _configManipulator;
- public DatabaseUpgradeStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, IIOHelper ioHelper)
+ public DatabaseUpgradeStep(
+ DatabaseBuilder databaseBuilder,
+ IRuntimeState runtime,
+ ILogger logger,
+ IUmbracoVersion umbracoVersion,
+ IGlobalSettings globalSettings,
+ IConnectionStrings connectionStrings,
+ IIOHelper ioHelper,
+ IConfigManipulator configManipulator)
{
_databaseBuilder = databaseBuilder;
_runtime = runtime;
@@ -33,6 +42,7 @@ namespace Umbraco.Web.Install.InstallSteps
_globalSettings = globalSettings;
_connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings));
_ioHelper = ioHelper;
+ _configManipulator = configManipulator;
}
public override Task ExecuteAsync(object model)
@@ -55,7 +65,7 @@ namespace Umbraco.Web.Install.InstallSteps
throw new InstallException("The database failed to upgrade. ERROR: " + result.Message);
}
- DatabaseInstallStep.HandleConnectionStrings(_logger, _ioHelper, _connectionStrings);
+ DatabaseInstallStep.HandleConnectionStrings(_logger, _ioHelper, _connectionStrings, _configManipulator);
}
return Task.FromResult(null);
diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs
index 9dde28e95a..bb77869e28 100644
--- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs
+++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Logging.Serilog
///
public class SerilogLogger : ILogger, IDisposable
{
- private readonly ICoreDebug _coreDebug;
+ private readonly ICoreDebugSettings _coreDebugSettings;
private readonly IIOHelper _ioHelper;
private readonly IMarchal _marchal;
@@ -26,9 +26,9 @@ namespace Umbraco.Core.Logging.Serilog
/// Initialize a new instance of the class with a configuration file.
///
///
- public SerilogLogger(ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal, FileInfo logConfigFile)
+ public SerilogLogger(ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal, FileInfo logConfigFile)
{
- _coreDebug = coreDebug;
+ _coreDebugSettings = coreDebugSettings;
_ioHelper = ioHelper;
_marchal = marchal;
@@ -37,9 +37,9 @@ namespace Umbraco.Core.Logging.Serilog
.CreateLogger();
}
- public SerilogLogger(ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal, LoggerConfiguration logConfig)
+ public SerilogLogger(ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal, LoggerConfiguration logConfig)
{
- _coreDebug = coreDebug;
+ _coreDebugSettings = coreDebugSettings;
_ioHelper = ioHelper;
_marchal = marchal;
@@ -51,7 +51,7 @@ namespace Umbraco.Core.Logging.Serilog
/// Creates a logger with some pre-defined configuration and remainder from config file
///
/// Used by UmbracoApplicationBase to get its logger.
- public static SerilogLogger CreateWithDefaultConfiguration(IHostingEnvironment hostingEnvironment, ISessionIdResolver sessionIdResolver, Func requestCacheGetter, ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal)
+ public static SerilogLogger CreateWithDefaultConfiguration(IHostingEnvironment hostingEnvironment, ISessionIdResolver sessionIdResolver, Func requestCacheGetter, ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal)
{
var loggerConfig = new LoggerConfiguration();
loggerConfig
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Logging.Serilog
.ReadFromConfigFile()
.ReadFromUserConfigFile();
- return new SerilogLogger(coreDebug, ioHelper, marchal, loggerConfig);
+ return new SerilogLogger(coreDebugSettings, ioHelper, marchal, loggerConfig);
}
///
@@ -179,7 +179,7 @@ namespace Umbraco.Core.Logging.Serilog
messageTemplate += "\r\nThe thread has been aborted, because the request has timed out.";
// dump if configured, or if stacktrace contains Monitor.ReliableEnter
- dump = _coreDebug.DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
+ dump = _coreDebugSettings.DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
// dump if it is ok to dump (might have a cap on number of dump...)
dump &= MiniDump.OkToDump(_ioHelper);
diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs
index 2074409ec8..987d3a98fb 100644
--- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs
+++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs
@@ -220,11 +220,5 @@ namespace Umbraco.Core.Manifest
return manifest;
}
-
- // purely for tests
- public IEnumerable ParseGridEditors(string text)
- {
- return _jsonSerializer.Deserialize>(text);
- }
}
}
diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
index a5a58dc9f1..17192fd69b 100644
--- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
+++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Migrations.Install
private readonly IIOHelper _ioHelper;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator;
- private readonly IConnectionStrings _connectionStrings;
+ private readonly IConfigManipulator _configManipulator;
private DatabaseSchemaResult _databaseSchemaValidationResult;
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Migrations.Install
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator,
- IConnectionStrings connectionStrings)
+ IConfigManipulator configManipulator)
{
_scopeProvider = scopeProvider;
_globalSettings = globalSettings;
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Migrations.Install
_ioHelper = ioHelper;
_umbracoVersion = umbracoVersion;
_dbProviderFactoryCreator = dbProviderFactoryCreator;
- _connectionStrings = connectionStrings;
+ _configManipulator = configManipulator;
}
#region Status
@@ -146,7 +146,7 @@ namespace Umbraco.Core.Migrations.Install
private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper)
{
- _connectionStrings.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
+ _configManipulator.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
var path = Path.Combine(ioHelper.GetRootDirectorySafe(), "App_Data", "Umbraco.sdf");
if (File.Exists(path) == false)
@@ -169,7 +169,7 @@ namespace Umbraco.Core.Migrations.Install
{
const string providerName = Constants.DbProviderNames.SqlServer;
- _connectionStrings.SaveConnectionString(connectionString, providerName);
+ _configManipulator.SaveConnectionString(connectionString, providerName);
_databaseFactory.Configure(connectionString, providerName);
}
@@ -185,7 +185,7 @@ namespace Umbraco.Core.Migrations.Install
{
var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName);
- _connectionStrings.SaveConnectionString(connectionString, providerName);
+ _configManipulator.SaveConnectionString(connectionString, providerName);
_databaseFactory.Configure(connectionString, providerName);
}
@@ -216,7 +216,7 @@ namespace Umbraco.Core.Migrations.Install
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
{
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
- _connectionStrings.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer);
+ _configManipulator.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer);
_databaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer);
}
diff --git a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs
index f7a2d6376b..59f63f4f15 100644
--- a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs
+++ b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs
@@ -191,7 +191,7 @@ namespace Umbraco.Web.Models.Mapping
target.Icon = source.Icon;
target.IconFilePath = target.IconIsClass
? string.Empty
- : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
+ : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
target.Trashed = source.Trashed;
target.Id = source.Id;
@@ -497,7 +497,7 @@ namespace Umbraco.Web.Models.Mapping
target.Icon = source.Icon;
target.IconFilePath = target.IconIsClass
? string.Empty
- : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
+ : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
target.Id = source.Id;
target.IsContainer = source.IsContainer;
target.IsElement = source.IsElement;
@@ -540,7 +540,7 @@ namespace Umbraco.Web.Models.Mapping
target.Icon = source.Icon;
target.IconFilePath = target.IconIsClass
? string.Empty
- : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
+ : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}";
target.Id = source.Id;
target.IsContainer = source.IsContainer;
target.IsElement = source.IsElement;
diff --git a/src/Umbraco.Infrastructure/Models/Property.cs b/src/Umbraco.Infrastructure/Models/Property.cs
index 36efbad404..89875811bd 100644
--- a/src/Umbraco.Infrastructure/Models/Property.cs
+++ b/src/Umbraco.Infrastructure/Models/Property.cs
@@ -98,7 +98,7 @@ namespace Umbraco.Core.Models
///
/// Represents a property value.
///
- public class PropertyValue : IPropertyValue
+ public class PropertyValue : IPropertyValue, IEquatable
{
// TODO: Either we allow change tracking at this class level, or we add some special change tracking collections to the Property
// class to deal with change tracking which variants have changed
@@ -143,6 +143,27 @@ namespace Umbraco.Core.Models
///
public IPropertyValue Clone()
=> new PropertyValue { _culture = _culture, _segment = _segment, PublishedValue = PublishedValue, EditedValue = EditedValue };
+
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as PropertyValue);
+ }
+
+ public bool Equals(PropertyValue other)
+ {
+ return other != null &&
+ _culture == other._culture &&
+ _segment == other._segment;
+ }
+
+ public override int GetHashCode()
+ {
+ var hashCode = -1254204277;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(_culture);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(_segment);
+ return hashCode;
+ }
}
private static readonly DelegateEqualityComparer