Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/booting-netcore

# Conflicts:
#	src/Umbraco.Core/IO/IOHelper.cs
#	src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
#	src/Umbraco.Tests.Common/TestHelperBase.cs
#	src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
#	src/Umbraco.Tests/Runtimes/StandaloneTests.cs
#	src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs
#	src/Umbraco.Web.UI.NetCore/Program.cs
#	src/Umbraco.Web.UI.NetCore/Startup.cs
#	src/Umbraco.Web/UmbracoApplication.cs
This commit is contained in:
Shannon
2020-03-23 15:50:01 +11:00
198 changed files with 2127 additions and 920 deletions
+3 -1
View File
@@ -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." }
}
+4 -1
View File
@@ -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." }
})
@@ -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<ITourSettings>(() => new TourSettings(_configuration));
configs.Add<ICoreDebugSettings>(() => new CoreDebugSettings(_configuration));
configs.Add<IRequestHandlerSettings>(() => new RequestHandlerSettings(_configuration));
configs.Add<ISecuritySettings>(() => new SecuritySettings(_configuration));
configs.Add<IUserPasswordConfiguration>(() => new UserPasswordConfigurationSettings(_configuration));
configs.Add<IMemberPasswordConfiguration>(() => new MemberPasswordConfigurationSettings(_configuration));
configs.Add<IKeepAliveSettings>(() => new KeepAliveSettings(_configuration));
configs.Add<IContentSettings>(() => new ContentSettings(_configuration));
configs.Add<IHealthChecksSettings>(() => new HealthChecksSettings(_configuration));
configs.Add<ILoggingSettings>(() => new LoggingSettings(_configuration));
configs.Add<IExceptionFilterSettings>(() => new ExceptionFilterSettings(_configuration));
configs.Add<IActiveDirectorySettings>(() => new ActiveDirectorySettings(_configuration));
configs.Add<IRuntimeSettings>(() => new RuntimeSettings(_configuration));
configs.Add<ITypeFinderSettings>(() => new TypeFinderSettings(_configuration));
configs.Add<INuCacheSettings>(() => new NuCacheSettings(_configuration));
configs.Add<IWebRoutingSettings>(() => new WebRoutingSettings(_configuration));
configs.Add<IIndexCreatorSettings>(() => new IndexCreatorSettings(_configuration));
configs.Add<IModelsBuilderConfig>(() => new ModelsBuilderConfig(_configuration));
configs.Add<IHostingSettings>(() => new HostingSettings(_configuration));
configs.Add<IGlobalSettings>(() => new GlobalSettings(_configuration));
configs.Add<IConnectionStrings>(() => new ConnectionStrings(_configuration));
configs.Add<IImagingSettings>(() => new ImagingSettings(_configuration));
return configs;
}
}
}
@@ -1,32 +0,0 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Configuration;
namespace Umbraco.Core.Configuration
{
/// <summary>
/// A case-insensitive configuration converter for enumerations.
/// </summary>
/// <typeparam name="T">The type of the enumeration.</typeparam>
public class CaseInsensitiveEnumConfigConverter<T> : 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<T>())));
}
}
}
+15 -20
View File
@@ -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<IGlobalSettings>(() => new GlobalSettings(ioHelper));
configs.Add(() => HostingSettings);
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
configs.Add(() => CoreDebug);
configs.Add(() => MachineKeyConfig);
configs.Add<IConnectionStrings>(() => new ConnectionStrings(ioHelper, logger));
configs.Add<IModelsBuilderConfig>(() => new ModelsBuilderConfig(ioHelper));
var configs = new Configs();
configs.Add<IGlobalSettings>(() => GlobalSettings);
configs.Add<IHostingSettings>(() => HostingSettings);
configs.Add<IHealthChecksSettings>(() => HealthChecksSettings);
configs.Add<ICoreDebugSettings>(() => CoreDebugSettings);
configs.Add<IConnectionStrings>(() => ConnectionStrings);
configs.Add<IModelsBuilderConfig>(() => ModelsBuilderConfig);
configs.Add<IIndexCreatorSettings>(() => IndexCreatorSettings);
configs.Add<INuCacheSettings>(() => NuCacheSettings);
configs.Add<ITypeFinderSettings>(() => TypeFinderSettings);
configs.Add<IRuntimeSettings>(() => RuntimeSettings);
configs.Add<IActiveDirectorySettings>(() => ActiveDirectorySettings);
configs.Add<IExceptionFilterSettings>(() => ExceptionFilterSettings);
configs.Add<ITourSettings>(() => TourSettings);
configs.Add<ILoggingSettings>(() => LoggingSettings);
configs.Add<IKeepAliveSettings>(() => KeepAliveSettings);
@@ -61,7 +57,6 @@ namespace Umbraco.Core.Configuration
configs.Add<IMemberPasswordConfiguration>(() => MemberPasswordConfigurationSettings);
configs.Add<IContentSettings>(() => ContentSettings);
configs.AddCoreConfigs(ioHelper);
return configs;
}
}
@@ -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<IDisabledHealthCheck> IHealthChecks.DisabledChecks
{
get { return DisabledChecks; }
}
IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
{
get { return NotificationSettings; }
}
}
}
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
namespace Umbraco.Configuration.Legacy
{
public class ActiveDirectorySettings : IActiveDirectorySettings
{
@@ -7,7 +7,7 @@ namespace Umbraco.Configuration.Implementations
{
private UmbracoSettingsSection _umbracoSettingsSection;
public UmbracoSettingsSection UmbracoSettingsSection
protected UmbracoSettingsSection UmbracoSettingsSection
{
get
{
@@ -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);
}
}
}
}
@@ -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);
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
namespace Umbraco.Configuration.Legacy
{
public class ExceptionFilterSettings : IExceptionFilterSettings
{
@@ -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;
/// <inheritdoc />
public LocalTempStorage LocalTempStorageLocation
{
get
{
var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
if (!string.IsNullOrWhiteSpace(setting))
return Enum<LocalTempStorage>.Parse(setting);
return LocalTempStorage.Default;
}
}
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
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
/// </summary>
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;
}
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
/// </summary>
@@ -203,15 +150,7 @@ namespace Umbraco.Core.Configuration
/// Gets the path to umbraco's root directory (/umbraco by default).
/// </summary>
/// <value>The path.</value>
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];
/// <summary>
/// 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");
}
/// <summary>
/// Gets the time out in minutes.
/// </summary>
@@ -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<IDisabledHealthCheck> DisabledChecks => HealthChecksSection.DisabledChecks;
public IHealthCheckNotificationSettings NotificationSettings => HealthChecksSection.NotificationSettings;
}
}
@@ -0,0 +1,52 @@
using System.Configuration;
namespace Umbraco.Core.Configuration.Legacy
{
public class HostingSettings : IHostingSettings
{
private bool? _debugMode;
/// <inheritdoc />
public LocalTempStorage LocalTempStorageLocation
{
get
{
var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
if (!string.IsNullOrWhiteSpace(setting))
return Enum<LocalTempStorage>.Parse(setting);
return LocalTempStorage.Default;
}
}
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
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();
}
}
}
}
@@ -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; }
@@ -6,14 +6,14 @@ using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.IO;
namespace Umbraco.Configuration
namespace Umbraco.Configuration.Legacy
{
/// <summary>
/// Represents the models builder configuration.
/// </summary>
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";
/// <summary>
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
/// </summary>
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
/// <summary>
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
/// </summary>
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}\".");
}
/// <summary>
/// Gets a value indicating whether the whole models experience is enabled.
@@ -1,7 +1,7 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
namespace Umbraco.Configuration.Legacy
{
public class NuCacheSettings : INuCacheSettings
{
@@ -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; }
}
}
@@ -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
{
@@ -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);
}
}
}
}
@@ -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<string>(Prefix+"Domain");
}
}
@@ -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();
}
}
}
@@ -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 =
@"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField =
{
new ImagingAutoFillUploadField
{
Alias = "umbracoFile"
}
};
private readonly IConfiguration _configuration;
public ContentSettings(IConfiguration configuration)
{
_configuration = configuration;
}
public string NotificationEmailAddress =>
_configuration.GetValue<string>(NotificationsPrefix+"Email");
public bool DisableHtmlEmail =>
_configuration.GetValue(NotificationsPrefix+"DisableHtmlEmail", false);
public IEnumerable<string> ImageFileTypes => _configuration.GetValue(
ImagingPrefix+"ImageFileTypes", new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" });
public IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties =>
_configuration.GetValue(ImagingPrefix+"AutoFillImageProperties",
DefaultImagingAutoFillUploadField);
public bool ResolveUrlsFromTextString =>
_configuration.GetValue(Prefix+"ResolveUrlsFromTextString", false);
public IEnumerable<IContentErrorPage> 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<string> DisallowedUploadFiles => _configuration.GetValue(
Prefix+"DisallowedUploadFiles",
new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" });
public IEnumerable<string> AllowedUploadFiles =>
_configuration.GetValue(Prefix+"AllowedUploadFiles", Array.Empty<string>());
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; }
}
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -0,0 +1,97 @@
using System;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration.Models
{
/// <summary>
/// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information
/// from web.config appsettings
/// </summary>
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<string>(Prefix + "Path");
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
public string ConfigurationStatus
{
get => _configuration.GetValue<string>(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<string>("From");
public string Host => _configurationSection.GetValue<string>("Host");
public int Port => _configurationSection.GetValue<int>("Port");
public string PickupDirectoryLocation => _configurationSection.GetValue<string>("PickupDirectoryLocation");
}
}
}
@@ -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<IDisabledHealthCheck> DisabledChecks => _configuration
.GetSection(Prefix+"DisabledChecks")
.GetChildren()
.Select(
x => new DisabledHealthCheck
{
Id = x.GetValue<Guid>("Id"),
DisabledOn = x.GetValue<DateTime>("DisabledOn"),
DisabledBy = x.GetValue<int>("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<string>("FirstRunTime");
public int PeriodInHours => _configurationSection.GetValue("PeriodInHours", 24);
public IReadOnlyDictionary<string, INotificationMethod> NotificationMethods => _configurationSection
.GetSection("NotificationMethods")
.GetChildren()
.ToDictionary(x => x.Key, x => (INotificationMethod) new NotificationMethod(x.Key, x));
public IEnumerable<IDisabledHealthCheck> DisabledChecks => _configurationSection
.GetSection("DisabledChecks").GetChildren().Select(
x => new DisabledHealthCheck
{
Id = x.GetValue<Guid>("Id"),
DisabledOn = x.GetValue<DateTime>("DisabledOn"),
DisabledBy = x.GetValue<int>("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<string, INotificationMethodSettings> 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; }
}
}
}
@@ -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;
}
/// <inheritdoc />
public LocalTempStorage LocalTempStorageLocation =>
_configuration.GetValue(Prefix+"LocalTempStorage", LocalTempStorage.Default);
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
public bool DebugMode => _configuration.GetValue(Prefix+":Debug", false);
}
}
@@ -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);
}
}
@@ -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<string>(Prefix + "LuceneDirectoryFactory");
}
}
@@ -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");
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -0,0 +1,86 @@
using Microsoft.Extensions.Configuration;
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration.Models
{
/// <summary>
/// Represents the models builder configuration.
/// </summary>
internal class ModelsBuilderConfig : IModelsBuilderConfig
{
private const string Prefix = Constants.Configuration.ConfigModelsBuilderPrefix;
private readonly IConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="ModelsBuilderConfig" /> class.
/// </summary>
public ModelsBuilderConfig(IConfiguration configuration)
{
_configuration = configuration;
}
public string DefaultModelsDirectory => "~/App_Data/Models";
/// <summary>
/// Gets a value indicating whether the whole models experience is enabled.
/// </summary>
/// <remarks>
/// <para>If this is false then absolutely nothing happens.</para>
/// <para>Default value is <c>false</c> which means that unless we have this setting, nothing happens.</para>
/// </remarks>
public bool Enable => _configuration.GetValue(Prefix+"Enable", false);
/// <summary>
/// Gets the models mode.
/// </summary>
public ModelsMode ModelsMode =>
_configuration.GetValue(Prefix+"ModelsMode", ModelsMode.Nothing);
/// <summary>
/// Gets the models namespace.
/// </summary>
/// <remarks>That value could be overriden by other (attribute in user's code...). Return default if no value was supplied.</remarks>
public string ModelsNamespace => _configuration.GetValue<string>(Prefix+"ModelsNamespace");
/// <summary>
/// Gets a value indicating whether we should enable the models factory.
/// </summary>
/// <remarks>Default value is <c>true</c> because no factory is enabled by default in Umbraco.</remarks>
public bool EnableFactory => _configuration.GetValue(Prefix+"EnableFactory", true);
/// <summary>
/// Gets a value indicating whether we should flag out-of-date models.
/// </summary>
/// <remarks>
/// 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 <c>false</c>.
/// </remarks>
public bool FlagOutOfDateModels =>
_configuration.GetValue(Prefix+"FlagOutOfDateModels", false) && !ModelsMode.IsLive();
/// <summary>
/// Gets the models directory.
/// </summary>
/// <remarks>Default is ~/App_Data/Models but that can be changed.</remarks>
public string ModelsDirectory =>
_configuration.GetValue(Prefix+"ModelsDirectory", "~/App_Data/Models");
/// <summary>
/// Gets a value indicating whether to accept an unsafe value for ModelsDirectory.
/// </summary>
/// <remarks>
/// An unsafe value is an absolute path, or a relative path pointing outside
/// of the website root.
/// </remarks>
public bool AcceptUnsafeModelsDirectory =>
_configuration.GetValue(Prefix+"AcceptUnsafeModelsDirectory", false);
/// <summary>
/// Gets a value indicating the debug log level.
/// </summary>
/// <remarks>0 means minimal (safe on live site), anything else means more and more details (maybe not safe).</remarks>
public int DebugLevel => _configuration.GetValue(Prefix+"DebugLevel", 0);
}
}
@@ -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<string>(Prefix+"BTreeBlockSize");
}
}
@@ -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<string>(Prefix+"ConvertUrlsToAscii").InvariantEquals("true");
public bool TryConvertUrlsToAscii => _configuration
.GetValue<string>(Prefix+"ConvertUrlsToAscii").InvariantEquals("try");
//We need to special handle ":", as this character is special in keys
public IEnumerable<IChar> CharCollection
{
get
{
var collection = _configuration.GetSection(Prefix + "CharCollection").GetChildren()
.Select(x => new CharItem()
{
Char = x.GetValue<string>("Char"),
Replacement = x.GetValue<string>("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; }
}
}
}
@@ -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<int?>(Prefix+"MaxRequestLength");
public int? MaxRequestLength => _configuration.GetValue<int?>(Prefix+"MaxRequestLength");
}
}
@@ -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<string>(Prefix + "AuthCookieDomain");
public bool UsernameIsEmail => _configuration.GetValue(Prefix + "UsernameIsEmail", true);
}
}
@@ -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);
}
}
@@ -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<string>(Prefix+"AssembliesAcceptingLoadExceptions");
}
}
@@ -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);
}
}
@@ -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<string>(Prefix + "UmbracoApplicationUrl");
}
}
@@ -22,6 +22,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
</ItemGroup>
@@ -1,33 +0,0 @@
using System.Configuration;
using Semver;
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public static class UmbracoVersionExtensions
{
/// <summary>
/// Gets the "local" version of the site.
/// </summary>
/// <remarks>
/// <para>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.</para>
/// </remarks>
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;
}
}
}
}
+3 -3
View File
@@ -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
}
/// <inheritdoc />
public void ClearOfType(string typeName)
public void ClearOfType(Type type)
{
InnerCache.ClearOfType(typeName);
InnerCache.ClearOfType(type);
}
/// <inheritdoc />
+3 -3
View File
@@ -71,16 +71,16 @@ namespace Umbraco.Core.Cache
}
/// <inheritdoc />
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);
}
/// <inheritdoc />
public virtual void ClearOfType<T>()
{
var typeOfT = typeof(T);
_items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT);
ClearOfType(typeOfT);
}
/// <inheritdoc />
@@ -12,12 +12,6 @@ namespace Umbraco.Core.Cache
/// </summary>
public class FastDictionaryAppCache : IAppCache
{
private readonly ITypeFinder _typeFinder;
public FastDictionaryAppCache(ITypeFinder typeFinder)
{
_typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
}
/// <summary>
/// Gets the internal items dictionary, for tests only!
@@ -83,9 +77,8 @@ namespace Umbraco.Core.Cache
}
/// <inheritdoc />
public void ClearOfType(string typeName)
public void ClearOfType(Type type)
{
var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
@@ -12,13 +12,6 @@ namespace Umbraco.Core.Cache
/// </summary>
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
}
/// <inheritdoc />
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
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestAppCache"/> class with a context, for unit tests!
/// </summary>
public HttpRequestAppCache(Func<IDictionary> requestItems, ITypeFinder typeFinder) : base(typeFinder)
public HttpRequestAppCache(Func<IDictionary> requestItems) : base()
{
ContextItems = requestItems;
}
+2 -2
View File
@@ -51,14 +51,14 @@ namespace Umbraco.Core.Cache
/// <summary>
/// Removes items of a specified type from the cache.
/// </summary>
/// <param name="typeName">The name of the type to remove.</param>
/// <param name="type">The type to remove.</param>
/// <remarks>
/// <para>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).</para>
/// <para>Performs a case-sensitive search.</para>
/// </remarks>
void ClearOfType(string typeName);
void ClearOfType(Type type);
/// <summary>
/// Removes items of a specified type from the cache.
+1 -1
View File
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Cache
{ }
/// <inheritdoc />
public virtual void ClearOfType(string typeName)
public virtual void ClearOfType(Type type)
{ }
/// <inheritdoc />
@@ -13,15 +13,13 @@ namespace Umbraco.Core.Cache
/// </summary>
public class ObjectCacheAppCache : IAppPolicyCache
{
private readonly ITypeFinder _typeFinder;
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
/// <summary>
/// Initializes a new instance of the <see cref="ObjectCacheAppCache"/>.
/// </summary>
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
}
/// <inheritdoc />
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
+1 -1
View File
@@ -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);
+1 -55
View File
@@ -13,16 +13,8 @@ namespace Umbraco.Core.Configuration
/// </remarks>
public class Configs
{
private readonly Func<string, object> _configSectionResolver;
public Configs(Func<string, object> configSectionResolver)
{
_configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver));
}
private readonly Dictionary<Type, Lazy<object>> _configs = new Dictionary<Type, Lazy<object>>();
private Dictionary<Type, Action<IRegister>> _registerings = new Dictionary<Type, Action<IRegister>>();
private Lazy<IFactory> _factory;
/// <summary>
/// Gets a configuration.
@@ -52,61 +44,15 @@ namespace Umbraco.Core.Configuration
_registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton);
}
/// <summary>
/// Adds a configuration, provided by a factory.
/// </summary>
public void Add<TConfig>(Func<IFactory, TConfig> 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<object>(() =>
{
if (!(_factory is null)) return _factory.Value.GetInstance<TConfig>();
throw new InvalidOperationException($"Cannot get configuration of type {typeOfConfig} during composition.");
});
_registerings[typeOfConfig] = register => register.Register(configFactory, Lifetime.Singleton);
}
/// <summary>
/// Adds a configuration, provided by a configuration section.
/// </summary>
public void Add<TConfig>(string sectionName)
where TConfig : class
{
Add(() => GetConfig<TConfig>(sectionName));
}
private TConfig GetConfig<TConfig>(string sectionName)
where TConfig : class
{
// note: need to use SafeCallContext here because ConfigurationManager.GetSection ends up getting AppDomain.Evidence
// which will want to serialize the call context including anything that is in there - what a mess!
using (new SafeCallContext())
{
if ((_configSectionResolver(sectionName) is TConfig config))
return config;
var ex = new InvalidOperationException($"Could not get configuration section \"{sectionName}\" from config files.");
throw ex;
}
}
/// <summary>
/// Registers configurations in a register.
/// </summary>
public void RegisterWith(IRegister register, Func<IFactory> factory)
public void RegisterWith(IRegister register)
{
// do it only once
if (_registerings == null)
throw new InvalidOperationException("Configurations have already been registered.");
_factory = new Lazy<IFactory>(factory);
register.Register(this);
foreach (var registering in _registerings.Values)
@@ -1,13 +1,7 @@
using System.IO;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
namespace Umbraco.Core
{
@@ -16,6 +10,9 @@ namespace Umbraco.Core
/// </summary>
public static class ConfigsExtensions
{
public static IImagingSettings Imaging(this Configs configs)
=> configs.GetConfig<IImagingSettings>();
public static IGlobalSettings Global(this Configs configs)
=> configs.GetConfig<IGlobalSettings>();
@@ -43,26 +40,10 @@ namespace Umbraco.Core
public static IWebRoutingSettings WebRouting(this Configs configs)
=> configs.GetConfig<IWebRoutingSettings>();
public static IHealthChecks HealthChecks(this Configs configs)
=> configs.GetConfig<IHealthChecks>();
public static IHealthChecksSettings HealthChecks(this Configs configs)
=> configs.GetConfig<IHealthChecksSettings>();
public static ICoreDebugSettings CoreDebug(this Configs configs)
=> configs.GetConfig<ICoreDebugSettings>();
public static IGridConfig Grids(this Configs configs)
=> configs.GetConfig<IGridConfig>();
public static ICoreDebug CoreDebug(this Configs configs)
=> configs.GetConfig<ICoreDebug>();
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<IGridConfig>(factory => new GridConfig(
factory.GetInstance<ILogger>(),
factory.GetInstance<AppCaches>(),
configDir,
factory.GetInstance<IManifestParser>(),
factory.GetInstance<IRuntimeState>().Debug));
}
}
}
@@ -1,45 +0,0 @@
using System;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public static class GlobalSettingsExtensions
{
private static string _mvcArea;
/// <summary>
/// This returns the string of the MVC Area route.
/// </summary>
/// <remarks>
/// 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".
/// </remarks>
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();
}
}
}
@@ -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; }
@@ -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<IGridEditorConfig> GetResult()
{
var configFolder = new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.Config));
var editors = new List<IGridEditorConfig>();
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<IEnumerable<GridEditor>>(sourceString));
}
catch (Exception ex)
{
_logger.Error<GridEditorsConfig>(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
Current.Logger.Error<GridEditorsConfig>(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;
}
}
}
}
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthChecks
public interface IHealthChecksSettings
{
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
IHealthCheckNotificationSettings NotificationSettings { get; }
@@ -0,0 +1,10 @@
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public interface IConfigManipulator
{
void RemoveConnectionString();
void SaveConnectionString(string connectionString, string providerName);
}
}
@@ -5,6 +5,6 @@ namespace Umbraco.Core.Configuration
{
public interface IConfigsFactory
{
Configs Create(IIOHelper ioHelper, ILogger logger);
Configs Create();
}
}
@@ -6,8 +6,5 @@ namespace Umbraco.Core.Configuration
{
get;
}
void RemoveConnectionString(string umbracoConnectionName);
void SaveConnectionString(string connectionString, string providerName);
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration
{
public interface ICoreDebug
public interface ICoreDebugSettings
{
/// <summary>
/// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed.
@@ -21,7 +21,7 @@
string ReservedPaths { get; }
/// <summary>
/// Gets the path to umbraco's root directory (/umbraco by default).
/// Gets the path to umbraco's root directory.
/// </summary>
string Path { get; }
@@ -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; }
}
}
@@ -1,7 +0,0 @@
namespace Umbraco.Core.Configuration
{
public interface IMachineKeyConfig
{
bool HasMachineKey { get;}
}
}
@@ -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; }
@@ -6,13 +6,11 @@
/// </summary>
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
@@ -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}\".");
}
}
}
@@ -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; }
@@ -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];
}
/// <summary>
/// Saves the connection string as a proper .net connection string in web.config.
/// <summary>
/// Saves the connection string as a proper .net connection string in web.config.
/// </summary>
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
/// <param name="connectionString">The connection string.</param>
/// <param name="providerName">The provider name.</param>
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<ConnectionStrings>("Saving connection string to {ConfigFile}.", fileSource);
_logger.Info<XmlConfigManipulator>("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
_logger.Info<ConnectionStrings>("Saved connection string to {ConfigFile}.", fileSource);
_logger.Info<XmlConfigManipulator>("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;
}
}
}
@@ -0,0 +1,18 @@
namespace Umbraco.Core
{
public static partial class Constants
{
public static class Configuration
{
/// <summary>
/// Case insensitive prefix for all configurations
/// </summary>
/// <remarks>
/// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}}
/// </remarks>
public const string ConfigPrefix = "Umbraco:CMS:";
public const string ConfigSecurityPrefix = ConfigPrefix+"Security:";
public const string ConfigModelsBuilderPrefix = ConfigPrefix+"ModelsBuilder:";
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
namespace Umbraco.Core
 namespace Umbraco.Core
{
public static partial class Constants
{
+3
View File
@@ -4,6 +4,9 @@ namespace Umbraco.Core.IO
{
public interface IIOHelper
{
string BackOfficePath { get; }
bool ForceNotHosted { get; set; }
char DirSepChar { get; }
+14 -1
View File
@@ -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 ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_globalSettings = globalSettings;
}
public string BackOfficePath
{
get
{
var path = _globalSettings.Path;
return string.IsNullOrEmpty(path) ? string.Empty : ResolveUrl(path);
}
}
/// <summary>
+35
View File
@@ -5,6 +5,8 @@ namespace Umbraco.Core.IO
{
public static class IOHelperExtensions
{
private static string _mvcArea;
/// <summary>
/// Tries to create a directory.
/// </summary>
@@ -35,5 +37,38 @@ namespace Umbraco.Core.IO
{
return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8);
}
/// <summary>
/// This returns the string of the MVC Area route.
/// </summary>
/// <remarks>
/// 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".
/// </remarks>
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();
}
}
}
@@ -17,7 +17,5 @@ namespace Umbraco.Core.Manifest
/// Parses a manifest.
/// </summary>
PackageManifest ParseManifest(string text);
IEnumerable<GridEditor> ParseGridEditors(string text);
}
}
+1
View File
@@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="System.ComponentModel.Annotations" Version="4.6.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
<PackageReference Include="System.Runtime.Caching" Version="4.6.0" />
</ItemGroup>
+8 -8
View File
@@ -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.
///
/// </remarks>
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
/// <param name="url"></param>
/// <param name="globalSettings"></param>
/// <returns></returns>
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;
}
@@ -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<JObject>(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");
}
/// <summary>
/// Returns the property value when case insensative
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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;
}
}
}
@@ -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))
@@ -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<HealthCheckNotificationMethodAttribute>();
@@ -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)
{
@@ -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<bool?>
{
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 : "";
/// <summary>
/// Don't display the view or execute if a machine key already exists
/// </summary>
/// <returns></returns>
private bool HasMachineKey()
{
return _machineKeyConfig.HasMachineKey;
}
/// <summary>
/// The step execution method
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public override Task<InstallSetupResult> ExecuteAsync(bool? model)
{
if (model.HasValue && model.Value == false) return Task.FromResult<InstallSetupResult>(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 <location> 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<InstallSetupResult>(null);
var generator = new MachineKeyGenerator();
var generatedSection = generator.GenerateConfigurationBlock();
systemWeb.Add(XElement.Parse(generatedSection));
xml.Save(fileName, SaveOptions.DisableFormatting);
return Task.FromResult<InstallSetupResult>(null);
}
public override bool RequiresExecution(bool? model)
{
return HasMachineKey() == false;
}
}
}
@@ -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<InstallSetupResult> 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<InstallSetupResult>(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
{

Some files were not shown because too many files have changed in this diff Show More