diff --git a/.github/BUILD.md b/.github/BUILD.md
index c6e870f396..ad33872423 100644
--- a/.github/BUILD.md
+++ b/.github/BUILD.md
@@ -43,6 +43,8 @@ If you only see a build.bat-file, you're probably on the wrong branch. If you sw
You might run into [Powershell quirks](#powershell-quirks).
+If it runs without errors; Hooray! Now you can continue with [the next step](CONTRIBUTING.md#how-do-i-begin) and open the solution and build it.
+
### Build Infrastructure
The Umbraco Build infrastructure relies on a PowerShell object. The object can be retrieved with:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index cea5859486..0101ac9d16 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -28,7 +28,7 @@ This project and everyone participating in it, is governed by the [our Code of C
[Working with the code](#working-with-the-code)
* [Building Umbraco from source code](#building-umbraco-from-source-code)
* [Working with the source code](#working-with-the-source-code)
- * [Making changes after the PR was opened](#making-changes-after-the-pr-was-opened)
+ * [Making changes after the PR is open](#making-changes-after-the-pr-is-open)
* [Which branch should I target for my contributions?](#which-branch-should-i-target-for-my-contributions)
* [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository)
@@ -65,7 +65,7 @@ Great question! The short version goes like this:
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
* **Commit** - done? Yay! 🎉 **Important:** create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`. When you have a branch, commit your changes. Don't commit to `v8/contrib`, create a new branch first.
* **Push** - great, now you can push the changes up to your fork on GitHub
- * **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here] (https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
+ * **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here](https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.

diff --git a/.gitignore b/.gitignore
index 12ad3299ad..5f2432313f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -100,6 +100,9 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js
+src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/navigation.controller.js
+src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.controller.js
+src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/utilities.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
@@ -164,3 +167,12 @@ build/temp/
# eof
/src/Umbraco.Web.UI.Client/TESTS-*.xml
/src/ApiDocs/api/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/Media/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/is-cache/*
+/src/Umbraco.Tests.Integration/App_Data/*
+/src/Umbraco.Tests.Integration/TEMP/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/assets/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/js/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/lib/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/views/*
+/src/Umbraco.Web.UI.NetCore/wwwroot/App_Data/TEMP/*
diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec
index 7630dad842..cfab130f0c 100644
--- a/build/NuSpecs/UmbracoCms.Web.nuspec
+++ b/build/NuSpecs/UmbracoCms.Web.nuspec
@@ -25,7 +25,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
-
+
diff --git a/build/build-bootstrap.ps1 b/build/build-bootstrap.ps1
index 71a25bfd7e..82c789ff22 100644
--- a/build/build-bootstrap.ps1
+++ b/build/build-bootstrap.ps1
@@ -22,6 +22,8 @@
# get NuGet
$cache = 4
$nuget = "$scriptTemp\nuget.exe"
+ # ensure the correct NuGet-source is used. This one is used by Umbraco
+ $nugetsourceUmbraco = "https://www.myget.org/F/umbracocore/api/v3/index.json"
if (-not $local)
{
$source = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
@@ -61,7 +63,7 @@
# get the build system
if (-not $local)
{
- $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease"
+ $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease", "-Source", $nugetsourceUmbraco
&$nuget install Umbraco.Build @params
if (-not $?) { throw "Failed to download Umbraco.Build." }
}
diff --git a/build/build.ps1 b/build/build.ps1
index ea07e4516f..6e124d1508 100644
--- a/build/build.ps1
+++ b/build/build.ps1
@@ -375,11 +375,14 @@
})
+ $nugetsourceUmbraco = "https://api.nuget.org/v3/index.json"
+
$ubuild.DefineMethod("RestoreNuGet",
{
Write-Host "Restore NuGet"
Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log"
- &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log"
+ $params = "-Source", $nugetsourceUmbraco
+ &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" @params
if (-not $?) { throw "Failed to restore NuGet packages." }
})
diff --git a/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs
new file mode 100644
index 0000000000..0cacab9e1d
--- /dev/null
+++ b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs
@@ -0,0 +1,50 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Configuration.Models;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.HealthChecks;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using ConnectionStrings = Umbraco.Configuration.Models.ConnectionStrings;
+using CoreDebugSettings = Umbraco.Configuration.Models.CoreDebugSettings;
+
+namespace Umbraco.Configuration
+{
+ public class AspNetCoreConfigsFactory : IConfigsFactory
+ {
+ private readonly IConfiguration _configuration;
+
+ public AspNetCoreConfigsFactory(IConfiguration configuration)
+ {
+ _configuration = configuration ?? throw new System.ArgumentNullException(nameof(configuration));
+ }
+
+ public Configs Create()
+ {
+ var configs = new Configs();
+
+ configs.Add(() => new TourSettings(_configuration));
+ configs.Add(() => new CoreDebugSettings(_configuration));
+ configs.Add(() => new RequestHandlerSettings(_configuration));
+ configs.Add(() => new SecuritySettings(_configuration));
+ configs.Add(() => new UserPasswordConfigurationSettings(_configuration));
+ configs.Add(() => new MemberPasswordConfigurationSettings(_configuration));
+ configs.Add(() => new KeepAliveSettings(_configuration));
+ configs.Add(() => new ContentSettings(_configuration));
+ configs.Add(() => new HealthChecksSettings(_configuration));
+ configs.Add(() => new LoggingSettings(_configuration));
+ configs.Add(() => new ExceptionFilterSettings(_configuration));
+ configs.Add(() => new ActiveDirectorySettings(_configuration));
+ configs.Add(() => new RuntimeSettings(_configuration));
+ configs.Add(() => new TypeFinderSettings(_configuration));
+ configs.Add(() => new NuCacheSettings(_configuration));
+ configs.Add(() => new WebRoutingSettings(_configuration));
+ configs.Add(() => new IndexCreatorSettings(_configuration));
+ configs.Add(() => new ModelsBuilderConfig(_configuration));
+ configs.Add(() => new HostingSettings(_configuration));
+ configs.Add(() => new GlobalSettings(_configuration));
+ configs.Add(() => new ConnectionStrings(_configuration));
+ configs.Add(() => new ImagingSettings(_configuration));
+
+ return configs;
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs b/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs
deleted file mode 100644
index f07e5133ef..0000000000
--- a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Globalization;
-using System.Linq;
-using System.Configuration;
-
-namespace Umbraco.Core.Configuration
-{
- ///
- /// A case-insensitive configuration converter for enumerations.
- ///
- /// The type of the enumeration.
- public class CaseInsensitiveEnumConfigConverter : ConfigurationConverterBase
- where T : struct
- {
- public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
- {
- if (data == null)
- throw new ArgumentNullException("data");
-
- //return Enum.Parse(typeof(T), (string)data, true);
-
- T value;
- if (Enum.TryParse((string)data, true, out value))
- return value;
-
- throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.",
- data, typeof(T).Name,
- string.Join(", ", Enum.GetValues(typeof(T)).Cast())));
- }
- }
-}
diff --git a/src/Umbraco.Configuration/ConfigsFactory.cs b/src/Umbraco.Configuration/ConfigsFactory.cs
index c09dc7b9f6..be6cee2d0c 100644
--- a/src/Umbraco.Configuration/ConfigsFactory.cs
+++ b/src/Umbraco.Configuration/ConfigsFactory.cs
@@ -1,34 +1,62 @@
-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;
namespace Umbraco.Core.Configuration
{
public class ConfigsFactory : IConfigsFactory
{
public IHostingSettings HostingSettings { get; } = new HostingSettings();
+ public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings();
+ public IIndexCreatorSettings IndexCreatorSettings { get; } = new IndexCreatorSettings();
+ public INuCacheSettings NuCacheSettings { get; } = new NuCacheSettings();
+ public ITypeFinderSettings TypeFinderSettings { get; } = new TypeFinderSettings();
+ public IRuntimeSettings RuntimeSettings { get; } = new RuntimeSettings();
+ public IActiveDirectorySettings ActiveDirectorySettings { get; } = new ActiveDirectorySettings();
+ public IExceptionFilterSettings ExceptionFilterSettings { get; } = new ExceptionFilterSettings();
+ public ITourSettings TourSettings { get; } = new TourSettings();
+ public ILoggingSettings LoggingSettings { get; } = new LoggingSettings();
+ public IKeepAliveSettings KeepAliveSettings { get; } = new KeepAliveSettings();
+ public IWebRoutingSettings WebRoutingSettings { get; } = new WebRoutingSettings();
+ public IRequestHandlerSettings RequestHandlerSettings { get; } = new RequestHandlerSettings();
+ public ISecuritySettings SecuritySettings { get; } = new SecuritySettings();
+ 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 ICoreDebug CoreDebug { get; } = new CoreDebug();
-
- public IUmbracoSettingsSection UmbracoSettings { get; }
-
- public Configs Create(IIOHelper ioHelper)
+ public Configs Create()
{
- var configs = new Configs(section => ConfigurationManager.GetSection(section));
- configs.Add(() => new GlobalSettings(ioHelper));
- configs.Add(() => HostingSettings);
+ var configs = new Configs();
- configs.Add("umbracoConfiguration/settings");
- configs.Add("umbracoConfiguration/HealthChecks");
+ configs.Add(() => GlobalSettings);
+ configs.Add(() => HostingSettings);
+ configs.Add(() => HealthChecksSettings);
+ configs.Add(() => CoreDebugSettings);
+ configs.Add(() => ConnectionStrings);
+ configs.Add(() => ModelsBuilderConfig);
+ configs.Add(() => IndexCreatorSettings);
+ configs.Add(() => NuCacheSettings);
+ configs.Add(() => TypeFinderSettings);
+ configs.Add(() => RuntimeSettings);
+ configs.Add(() => ActiveDirectorySettings);
+ configs.Add(() => ExceptionFilterSettings);
+ configs.Add(() => TourSettings);
+ configs.Add(() => LoggingSettings);
+ configs.Add(() => KeepAliveSettings);
+ configs.Add(() => WebRoutingSettings);
+ configs.Add(() => RequestHandlerSettings);
+ configs.Add(() => SecuritySettings);
+ configs.Add(() => UserPasswordConfigurationSettings);
+ configs.Add(() => MemberPasswordConfigurationSettings);
+ configs.Add(() => ContentSettings);
- // Password configuration is held within IUmbracoSettingsSection from umbracoConfiguration/settings but we'll add explicitly
- // so it can be independently retrieved in classes that need it.
- configs.AddPasswordConfigurations();
-
- configs.Add(() => CoreDebug);
- configs.Add(() => new ConnectionStrings(ioHelper));
- configs.AddCoreConfigs(ioHelper);
return configs;
}
}
diff --git a/src/Umbraco.Configuration/ConnectionStrings.cs b/src/Umbraco.Configuration/ConnectionStrings.cs
deleted file mode 100644
index 6a00974831..0000000000
--- a/src/Umbraco.Configuration/ConnectionStrings.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Configuration;
-using System.Linq;
-using System.Xml.Linq;
-using Umbraco.Core.IO;
-
-namespace Umbraco.Core.Configuration
-{
- public class ConnectionStrings : IConnectionStrings
- {
- private readonly IIOHelper _ioHelper;
-
- public ConnectionStrings(IIOHelper ioHelper)
- {
- _ioHelper = ioHelper;
- }
-
- 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)
- {
- var fileName = _ioHelper.MapPath(string.Format("{0}/web.config", _ioHelper.Root));
- var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
-
- var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
- var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
-
- if (setting != null)
- {
- setting.Remove();
- xml.Save(fileName, SaveOptions.DisableFormatting);
- ConfigurationManager.RefreshSection("appSettings");
- }
- var settings = ConfigurationManager.ConnectionStrings[key];
- }
- }
-}
diff --git a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
index 90a7d8c567..373d846567 100644
--- a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
+++ b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs
@@ -1,10 +1,9 @@
using System;
-using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
- public class HealthChecksSection : ConfigurationSection, IHealthChecks
+ public class HealthChecksSection : ConfigurationSection
{
private const string DisabledChecksKey = "disabledChecks";
private const string NotificationSettingsKey = "notificationSettings";
@@ -21,14 +20,5 @@ namespace Umbraco.Core.Configuration.HealthChecks
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
}
- IEnumerable IHealthChecks.DisabledChecks
- {
- get { return DisabledChecks; }
- }
-
- IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
- {
- get { return NotificationSettings; }
- }
}
}
diff --git a/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs
new file mode 100644
index 0000000000..ef100afed6
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs
@@ -0,0 +1,15 @@
+using System.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class ActiveDirectorySettings : IActiveDirectorySettings
+ {
+ public ActiveDirectorySettings()
+ {
+ ActiveDirectoryDomain = ConfigurationManager.AppSettings["ActiveDirectoryDomain"];
+ }
+
+ public string ActiveDirectoryDomain { get; }
+ }
+}
diff --git a/src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs
new file mode 100644
index 0000000000..0302a7ea31
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs
@@ -0,0 +1,22 @@
+using System.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal abstract class ConfigurationManagerConfigBase
+ {
+ private UmbracoSettingsSection _umbracoSettingsSection;
+
+ protected UmbracoSettingsSection UmbracoSettingsSection
+ {
+ get
+ {
+ if (_umbracoSettingsSection is null)
+ {
+ _umbracoSettingsSection = ConfigurationManager.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection;
+ }
+ return _umbracoSettingsSection;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs
new file mode 100644
index 0000000000..a02c351118
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs
@@ -0,0 +1,17 @@
+using System.Configuration;
+
+namespace Umbraco.Core.Configuration
+{
+ public class ConnectionStrings : IConnectionStrings
+ {
+ public ConfigConnectionString this[string key]
+ {
+ get
+ {
+ var settings = ConfigurationManager.ConnectionStrings[key];
+ if (settings == null) return null;
+ return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/ContentSettings.cs b/src/Umbraco.Configuration/Legacy/ContentSettings.cs
new file mode 100644
index 0000000000..1c3f543bfe
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ContentSettings.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class ContentSettings : ConfigurationManagerConfigBase, IContentSettings
+ {
+ public string NotificationEmailAddress => UmbracoSettingsSection.Content.Notifications.NotificationEmailAddress;
+ public bool DisableHtmlEmail => UmbracoSettingsSection.Content.Notifications.DisableHtmlEmail;
+ public IEnumerable ImageFileTypes => UmbracoSettingsSection.Content.Imaging.ImageFileTypes;
+ public IEnumerable ImageAutoFillProperties => UmbracoSettingsSection.Content.Imaging.ImageAutoFillProperties;
+ public bool ResolveUrlsFromTextString => UmbracoSettingsSection.Content.ResolveUrlsFromTextString;
+ public IEnumerable Error404Collection => UmbracoSettingsSection.Content.Error404Collection;
+ public string PreviewBadge => UmbracoSettingsSection.Content.PreviewBadge;
+ public MacroErrorBehaviour MacroErrorBehaviour => UmbracoSettingsSection.Content.MacroErrors;
+ public IEnumerable DisallowedUploadFiles => UmbracoSettingsSection.Content.DisallowedUploadFiles;
+ public IEnumerable AllowedUploadFiles => UmbracoSettingsSection.Content.AllowedUploadFiles;
+ public bool ShowDeprecatedPropertyEditors => UmbracoSettingsSection.Content.ShowDeprecatedPropertyEditors;
+ public string LoginBackgroundImage => UmbracoSettingsSection.Content.LoginBackgroundImage;
+ }
+}
diff --git a/src/Umbraco.Configuration/CoreDebug.cs b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
similarity index 87%
rename from src/Umbraco.Configuration/CoreDebug.cs
rename to src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
index 0ff3274565..4902d4489f 100644
--- a/src/Umbraco.Configuration/CoreDebug.cs
+++ b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs
@@ -3,9 +3,9 @@ using System.Configuration;
namespace Umbraco.Core.Configuration
{
- public class CoreDebug : ICoreDebug
+ public class CoreDebugSettings : ICoreDebugSettings
{
- public CoreDebug()
+ public CoreDebugSettings()
{
var appSettings = ConfigurationManager.AppSettings;
LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase);
diff --git a/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs
new file mode 100644
index 0000000000..50e2207485
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs
@@ -0,0 +1,18 @@
+using System.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class ExceptionFilterSettings : IExceptionFilterSettings
+ {
+ public ExceptionFilterSettings()
+ {
+ if (bool.TryParse(ConfigurationManager.AppSettings["Umbraco.Web.DisableModelBindingExceptionFilter"],
+ out var disabled))
+ {
+ Disabled = disabled;
+ }
+ }
+ public bool Disabled { get; }
+ }
+}
diff --git a/src/Umbraco.Configuration/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
similarity index 85%
rename from src/Umbraco.Configuration/GlobalSettings.cs
rename to src/Umbraco.Configuration/Legacy/GlobalSettings.cs
index a44f7ae636..d93297ca90 100644
--- a/src/Umbraco.Configuration/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
@@ -3,59 +3,12 @@ using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Xml.Linq;
+using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core.IO;
-namespace Umbraco.Core.Configuration
+namespace Umbraco.Core.Configuration.Legacy
{
- public class HostingSettings : IHostingSettings
- {
- private bool? _debugMode;
-
- ///
- public LocalTempStorage LocalTempStorageLocation
- {
- get
- {
- var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
- if (!string.IsNullOrWhiteSpace(setting))
- return Enum.Parse(setting);
-
- return LocalTempStorage.Default;
- }
- }
-
- ///
- /// Gets a value indicating whether umbraco is running in [debug mode].
- ///
- /// true if [debug mode]; otherwise, false.
- public bool DebugMode
- {
- get
- {
- if (!_debugMode.HasValue)
- {
- try
- {
- if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation)
- {
- var debugElement = compilation.ElementInformation.Properties["debug"];
-
- _debugMode = debugElement != null && (debugElement.Value is bool debug && debug);
-
- }
- }
- catch
- {
- _debugMode = false;
- }
- }
-
- return _debugMode.GetValueOrDefault();
- }
- }
- }
-
// TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults!
// TODO: need to massively cleanup these configuration classes
@@ -64,7 +17,6 @@ namespace Umbraco.Core.Configuration
///
public class GlobalSettings : IGlobalSettings
{
- private readonly IIOHelper _ioHelper;
// TODO these should not be static
private static string _reservedPaths;
@@ -74,11 +26,6 @@ namespace Umbraco.Core.Configuration
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
- public GlobalSettings(IIOHelper ioHelper)
- {
- _ioHelper = ioHelper;
- }
-
///
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
///
@@ -184,8 +131,8 @@ namespace Umbraco.Core.Configuration
if (_reservedPaths != null) return _reservedPaths;
var reservedPaths = StaticReservedPaths;
- var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path) && !ConfigurationManager.AppSettings[Constants.AppSettings.Path].IsNullOrWhiteSpace()
- ? ConfigurationManager.AppSettings[Constants.AppSettings.Path]
+ var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.UmbracoPath) && !ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath].IsNullOrWhiteSpace()
+ ? ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath]
: "~/umbraco";
//always add the umbraco path to the list
reservedPaths += umbPath.EnsureEndsWith(',');
@@ -199,20 +146,6 @@ namespace Umbraco.Core.Configuration
}
}
- ///
- /// Gets the path to umbraco's root directory (/umbraco by default).
- ///
- /// The path.
- public string Path
- {
- get
- {
- return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path)
- ? _ioHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path])
- : string.Empty;
- }
- }
-
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
///
@@ -227,7 +160,7 @@ namespace Umbraco.Core.Configuration
}
set
{
- SaveSetting(Constants.AppSettings.ConfigurationStatus, value, _ioHelper);
+ SaveSetting(Constants.AppSettings.ConfigurationStatus, value, Current.IOHelper); //TODO remove
}
}
@@ -238,7 +171,7 @@ namespace Umbraco.Core.Configuration
/// Value of the setting to be saved.
internal static void SaveSetting(string key, string value, IIOHelper ioHelper)
{
- var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
+ var fileName = ioHelper.MapPath("~/web.config");
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
@@ -254,7 +187,7 @@ namespace Umbraco.Core.Configuration
ConfigurationManager.RefreshSection("appSettings");
}
-
+
///
/// Gets the time out in minutes.
///
@@ -382,6 +315,10 @@ namespace Umbraco.Core.Configuration
private string _databaseFactoryServerVersion;
public string DatabaseFactoryServerVersion => GetterWithDefaultValue(Constants.AppSettings.Debug.DatabaseFactoryServerVersion, string.Empty, ref _databaseFactoryServerVersion);
+ private string _mainDomLock;
+
+ public string MainDomLock => GetterWithDefaultValue(Constants.AppSettings.MainDomLock, string.Empty, ref _mainDomLock);
+
private T GetterWithDefaultValue(string appSettingKey, T defaultValue, ref T backingField)
{
if (backingField != null) return backingField;
@@ -407,5 +344,22 @@ namespace Umbraco.Core.Configuration
return backingField;
}
+
+ ///
+ /// Gets the path to the razor file used when no published content is available.
+ ///
+ public string NoNodesViewPath
+ {
+ get
+ {
+ var configuredValue = ConfigurationManager.AppSettings[Constants.AppSettings.NoNodesViewPath];
+ if (!string.IsNullOrWhiteSpace(configuredValue))
+ {
+ return configuredValue;
+ }
+
+ return "~/config/splashes/NoNodes.cshtml";
+ }
+ }
}
}
diff --git a/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs
new file mode 100644
index 0000000000..23385d1378
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Configuration;
+using Umbraco.Core.Configuration.HealthChecks;
+
+namespace Umbraco.Core.Configuration.Legacy
+{
+ public class HealthChecksSettings : IHealthChecksSettings
+ {
+ private HealthChecksSection _healthChecksSection;
+
+ private HealthChecksSection HealthChecksSection
+ {
+ get
+ {
+ if (_healthChecksSection is null)
+ {
+ _healthChecksSection = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as HealthChecksSection;
+ }
+ return _healthChecksSection;
+ }
+ }
+
+ public IEnumerable DisabledChecks => HealthChecksSection.DisabledChecks;
+ public IHealthCheckNotificationSettings NotificationSettings => HealthChecksSection.NotificationSettings;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/HostingSettings.cs b/src/Umbraco.Configuration/Legacy/HostingSettings.cs
new file mode 100644
index 0000000000..1858e8a4a4
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/HostingSettings.cs
@@ -0,0 +1,54 @@
+using System.Configuration;
+
+namespace Umbraco.Core.Configuration.Legacy
+{
+ public class HostingSettings : IHostingSettings
+ {
+ private bool? _debugMode;
+
+ ///
+ public LocalTempStorage LocalTempStorageLocation
+ {
+ get
+ {
+ var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage];
+ if (!string.IsNullOrWhiteSpace(setting))
+ return Enum.Parse(setting);
+
+ return LocalTempStorage.Default;
+ }
+ }
+
+ public string ApplicationVirtualPath => null;
+
+ ///
+ /// Gets a value indicating whether umbraco is running in [debug mode].
+ ///
+ /// true if [debug mode]; otherwise, false.
+ public bool DebugMode
+ {
+ get
+ {
+ if (!_debugMode.HasValue)
+ {
+ try
+ {
+ if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation)
+ {
+ var debugElement = compilation.ElementInformation.Properties["debug"];
+
+ _debugMode = debugElement != null && (debugElement.Value is bool debug && debug);
+
+ }
+ }
+ catch
+ {
+ _debugMode = false;
+ }
+ }
+
+ return _debugMode.GetValueOrDefault();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs
new file mode 100644
index 0000000000..d023d46246
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs
@@ -0,0 +1,15 @@
+using System.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class IndexCreatorSettings : IIndexCreatorSettings
+ {
+ public IndexCreatorSettings()
+ {
+ LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"];
+ }
+
+ public string LuceneDirectoryFactory { get; }
+ }
+}
diff --git a/src/Umbraco.Configuration/InnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/InnerTextConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs
new file mode 100644
index 0000000000..0b8315d447
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs
@@ -0,0 +1,10 @@
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class KeepAliveSettings : ConfigurationManagerConfigBase, IKeepAliveSettings
+ {
+ public bool DisableKeepAliveTask => UmbracoSettingsSection.KeepAlive.DisableKeepAliveTask;
+ public string KeepAlivePingUrl => UmbracoSettingsSection.KeepAlive.KeepAlivePingUrl;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/LoggingSettings.cs b/src/Umbraco.Configuration/Legacy/LoggingSettings.cs
new file mode 100644
index 0000000000..020b0c0e64
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/LoggingSettings.cs
@@ -0,0 +1,9 @@
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class LoggingSettings : ConfigurationManagerConfigBase, ILoggingSettings
+ {
+ public int MaxLogAge => UmbracoSettingsSection.Logging.MaxLogAge;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..e42b02de73
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs
@@ -0,0 +1,16 @@
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class MemberPasswordConfigurationSettings : ConfigurationManagerConfigBase, IMemberPasswordConfiguration
+ {
+ public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength;
+ public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit;
+ public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit;
+ public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase;
+ public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase;
+ public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding;
+ public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType;
+ public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout;
+ }
+}
diff --git a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
similarity index 76%
rename from src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsBuilderConfig.cs
rename to src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
index d0137ed2b2..f6395b23b4 100644
--- a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsBuilderConfig.cs
+++ b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs
@@ -2,18 +2,18 @@
using System.Configuration;
using System.IO;
using System.Threading;
-using System.Web.Configuration;
+using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.IO;
-namespace Umbraco.ModelsBuilder.Embedded.Configuration
+namespace Umbraco.Configuration.Legacy
{
///
/// Represents the models builder configuration.
///
public class ModelsBuilderConfig : IModelsBuilderConfig
{
- private readonly IIOHelper _ioHelper;
+
private const string Prefix = "Umbraco.ModelsBuilder.";
private object _modelsModelLock;
private bool _modelsModelConfigured;
@@ -21,23 +21,21 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
private object _flagOutOfDateModelsLock;
private bool _flagOutOfDateModelsConfigured;
private bool _flagOutOfDateModels;
- public const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
- public string DefaultModelsDirectory => _ioHelper.MapPath("~/App_Data/Models");
+
+ public string DefaultModelsDirectory => "~/App_Data/Models";
///
/// Initializes a new instance of the class.
///
- public ModelsBuilderConfig(IIOHelper ioHelper)
+ public ModelsBuilderConfig()
{
- _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
-
// giant kill switch, default: false
// must be explicitely set to true for anything else to happen
Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true";
// ensure defaults are initialized for tests
- ModelsNamespace = DefaultModelsNamespace;
+ ModelsNamespace = Constants.ModelsBuilder.DefaultModelsNamespace;
ModelsDirectory = DefaultModelsDirectory;
DebugLevel = 0;
@@ -59,12 +57,8 @@ namespace Umbraco.ModelsBuilder.Embedded.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.ModelsBuilder.Embedded.Configuration
///
/// Initializes a new instance of the class.
///
- public ModelsBuilderConfig(IIOHelper ioHelper,
+ public ModelsBuilderConfig(
bool enable = false,
ModelsMode modelsMode = ModelsMode.Nothing,
string modelsNamespace = null,
@@ -91,11 +85,10 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
bool acceptUnsafeModelsDirectory = false,
int debugLevel = 0)
{
- _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
Enable = enable;
_modelsMode = modelsMode;
- ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? DefaultModelsNamespace : modelsNamespace;
+ ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? Constants.ModelsBuilder.DefaultModelsNamespace : modelsNamespace;
EnableFactory = enableFactory;
_flagOutOfDateModels = flagOutOfDateModels;
ModelsDirectory = string.IsNullOrWhiteSpace(modelsDirectory) ? DefaultModelsDirectory : modelsDirectory;
@@ -103,36 +96,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
DebugLevel = debugLevel;
}
- // internal for tests
- internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe)
- {
- // making sure it is safe, ie under the website root,
- // unless AcceptUnsafeModelsDirectory and then everything is OK.
- if (!Path.IsPathRooted(root))
- throw new ConfigurationErrorsException($"Root is not rooted \"{root}\".");
-
- if (config.StartsWith("~/"))
- {
- var dir = Path.Combine(root, config.TrimStart("~/"));
-
- // sanitize - GetFullPath will take care of any relative
- // segments in path, eg '../../foo.tmp' - it may throw a SecurityException
- // if the combined path reaches illegal parts of the filesystem
- dir = Path.GetFullPath(dir);
- root = Path.GetFullPath(root);
-
- if (!dir.StartsWith(root) && !acceptUnsafe)
- throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
-
- return dir;
- }
-
- if (acceptUnsafe)
- return Path.GetFullPath(config);
-
- throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
- }
///
/// Gets a value indicating whether the whole models experience is enabled.
@@ -174,8 +138,13 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
{
get
{
- var section = (CompilationSection)ConfigurationManager.GetSection("system.web/compilation");
- return section != null && section.Debug;
+ if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection section &&
+ bool.TryParse(section.ElementInformation.Properties["debug"].Value.ToString(), out var isDebug))
+ {
+ return isDebug;
+ }
+
+ return false;
}
}
diff --git a/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs
new file mode 100644
index 0000000000..25f52a5c7d
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class NuCacheSettings : INuCacheSettings
+ {
+ public NuCacheSettings()
+ {
+ BTreeBlockSize = ConfigurationManager.AppSettings["Umbraco.Web.PublishedCache.NuCache.BTree.BlockSize"];
+ }
+ public string BTreeBlockSize { get; }
+ }
+}
diff --git a/src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/RawXmlConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs
similarity index 100%
rename from src/Umbraco.Configuration/RawXmlConfigurationElement.cs
rename to src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs
diff --git a/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs
new file mode 100644
index 0000000000..1c54f4d475
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class RequestHandlerSettings : ConfigurationManagerConfigBase, IRequestHandlerSettings
+ {
+ public bool AddTrailingSlash => UmbracoSettingsSection?.RequestHandler?.AddTrailingSlash ?? true;
+ public bool ConvertUrlsToAscii => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.ConvertUrlsToAscii.InvariantEquals("true") ?? false;
+ public bool TryConvertUrlsToAscii => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.ConvertUrlsToAscii.InvariantEquals("try") ?? false;
+ public IEnumerable CharCollection => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.CharCollection ?? Enumerable.Empty();
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs
new file mode 100644
index 0000000000..200642a819
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs
@@ -0,0 +1,29 @@
+using System.Configuration;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class RuntimeSettings : IRuntimeSettings
+ {
+ public RuntimeSettings()
+ {
+ if (ConfigurationManager.GetSection("system.web/httpRuntime") is ConfigurationSection section)
+ {
+ var maxRequestLengthProperty = section.ElementInformation.Properties["maxRequestLength"];
+ if (maxRequestLengthProperty != null && maxRequestLengthProperty.Value is int requestLength)
+ {
+ MaxRequestLength = requestLength;
+ }
+
+ var maxQueryStringProperty = section.ElementInformation.Properties["maxQueryStringLength"];
+ if (maxQueryStringProperty != null && maxQueryStringProperty.Value is int maxQueryStringLength)
+ {
+ MaxQueryStringLength = maxQueryStringLength;
+ }
+ }
+ }
+ public int? MaxQueryStringLength { get; }
+ public int? MaxRequestLength { get; }
+
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/SecuritySettings.cs b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs
new file mode 100644
index 0000000000..b7e39b0608
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs
@@ -0,0 +1,14 @@
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class SecuritySettings : ConfigurationManagerConfigBase, ISecuritySettings
+ {
+ public bool KeepUserLoggedIn => UmbracoSettingsSection.Security.KeepUserLoggedIn;
+ public bool HideDisabledUsersInBackoffice => UmbracoSettingsSection.Security.HideDisabledUsersInBackoffice;
+ public bool AllowPasswordReset => UmbracoSettingsSection.Security.AllowPasswordReset;
+ public string AuthCookieName => UmbracoSettingsSection.Security.AuthCookieName;
+ public string AuthCookieDomain => UmbracoSettingsSection.Security.AuthCookieDomain;
+ public bool UsernameIsEmail => UmbracoSettingsSection.Security.UsernameIsEmail;
+ }
+}
diff --git a/src/Umbraco.Configuration/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
similarity index 100%
rename from src/Umbraco.Configuration/SmtpSettings.cs
rename to src/Umbraco.Configuration/Legacy/SmtpSettings.cs
diff --git a/src/Umbraco.Configuration/Legacy/TourSettings.cs b/src/Umbraco.Configuration/Legacy/TourSettings.cs
new file mode 100644
index 0000000000..134c3c48d5
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/TourSettings.cs
@@ -0,0 +1,9 @@
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class TourSettings : ConfigurationManagerConfigBase, ITourSettings
+ {
+ public bool EnableTours => UmbracoSettingsSection.BackOffice.Tours.EnableTours;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs
new file mode 100644
index 0000000000..b1009f754b
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs
@@ -0,0 +1,17 @@
+using System.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Legacy
+{
+ public class TypeFinderSettings : ITypeFinderSettings
+ {
+ public TypeFinderSettings()
+ {
+ AssembliesAcceptingLoadExceptions = ConfigurationManager.AppSettings[
+ Constants.AppSettings.AssembliesAcceptingLoadExceptions];
+ }
+
+ public string AssembliesAcceptingLoadExceptions { get; }
+ }
+}
diff --git a/src/Umbraco.Configuration/UmbracoConfigurationSection.cs b/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs
similarity index 100%
rename from src/Umbraco.Configuration/UmbracoConfigurationSection.cs
rename to src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs
diff --git a/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..51dd645c42
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs
@@ -0,0 +1,15 @@
+using Umbraco.Core.Configuration;
+namespace Umbraco.Configuration.Implementations
+{
+ internal class UserPasswordConfigurationSettings : ConfigurationManagerConfigBase, IUserPasswordConfiguration
+ {
+ public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength;
+ public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit;
+ public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit;
+ public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase;
+ public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase;
+ public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding;
+ public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType;
+ public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout;
+ }
+}
diff --git a/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs b/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs
new file mode 100644
index 0000000000..cfca66822b
--- /dev/null
+++ b/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs
@@ -0,0 +1,16 @@
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Implementations
+{
+ internal class WebRoutingSettings : ConfigurationManagerConfigBase, IWebRoutingSettings
+ {
+ public bool TrySkipIisCustomErrors => UmbracoSettingsSection?.WebRouting?.TrySkipIisCustomErrors ?? false;
+ public bool InternalRedirectPreservesTemplate => UmbracoSettingsSection?.WebRouting?.InternalRedirectPreservesTemplate ?? false;
+ public bool DisableAlternativeTemplates => UmbracoSettingsSection?.WebRouting?.DisableAlternativeTemplates ?? false;
+ public bool ValidateAlternativeTemplates => UmbracoSettingsSection?.WebRouting?.ValidateAlternativeTemplates ?? false;
+ public bool DisableFindContentByIdPath => UmbracoSettingsSection?.WebRouting?.DisableFindContentByIdPath ?? false;
+ public bool DisableRedirectUrlTracking => UmbracoSettingsSection?.WebRouting?.DisableRedirectUrlTracking ?? false;
+ public string UrlProviderMode => UmbracoSettingsSection?.WebRouting?.UrlProviderMode ?? "Auto";
+ public string UmbracoApplicationUrl => UmbracoSettingsSection?.WebRouting?.UmbracoApplicationUrl;
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs
new file mode 100644
index 0000000000..015fb17a8e
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ActiveDirectorySettings : IActiveDirectorySettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "ActiveDirectory:";
+ private readonly IConfiguration _configuration;
+
+ public ActiveDirectorySettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string ActiveDirectoryDomain => _configuration.GetValue(Prefix+"Domain");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Configuration/Models/ConnectionStrings.cs
new file mode 100644
index 0000000000..22a0bde571
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ConnectionStrings.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Data.Common;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ public class ConnectionStrings : IConnectionStrings
+ {
+ private readonly IConfiguration _configuration;
+
+ public ConnectionStrings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public ConfigConnectionString this[string key]
+ {
+ get
+ {
+ var connectionString = _configuration.GetConnectionString(key);
+ var provider = ParseProvider(connectionString);
+ return new ConfigConnectionString(connectionString, provider, key);
+ }
+ set => throw new NotImplementedException();
+ }
+
+ private string ParseProvider(string connectionString)
+ {
+ if (string.IsNullOrEmpty(connectionString))
+ {
+ return null;
+ }
+
+ var builder = new DbConnectionStringBuilder();
+
+ builder.ConnectionString = connectionString;
+
+ if (builder.TryGetValue("Data Source", out var ds) && ds is string dataSource)
+ {
+ if (dataSource.EndsWith(".sdf"))
+ {
+ return Constants.DbProviderNames.SqlCe;
+ }
+ }
+
+ if (builder.TryGetValue("Server", out var s) && s is string server && builder.TryGetValue("Database", out var db) && db is string database)
+ {
+ if (!string.IsNullOrEmpty(server) && !string.IsNullOrEmpty(database))
+ {
+ return Constants.DbProviderNames.SqlServer;
+ }
+ }
+
+ throw new ArgumentException("Cannot determine provider name from connection string", nameof(connectionString));
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ContentSettings.cs b/src/Umbraco.Configuration/Models/ContentSettings.cs
new file mode 100644
index 0000000000..5bc31814b7
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ContentSettings.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Macros;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ContentSettings : IContentSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Content:";
+ private const string NotificationsPrefix = Prefix + "Notifications:";
+ private const string ImagingPrefix = Prefix + "Imaging:";
+ private const string DefaultPreviewBadge =
+ @"";
+
+ private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField =
+ {
+ new ImagingAutoFillUploadField
+ {
+ Alias = "umbracoFile"
+ }
+ };
+
+ private readonly IConfiguration _configuration;
+
+ public ContentSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string NotificationEmailAddress =>
+ _configuration.GetValue(NotificationsPrefix+"Email");
+
+ public bool DisableHtmlEmail =>
+ _configuration.GetValue(NotificationsPrefix+"DisableHtmlEmail", false);
+
+ public IEnumerable ImageFileTypes => _configuration.GetValue(
+ ImagingPrefix+"ImageFileTypes", new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" });
+
+ public IEnumerable ImageAutoFillProperties =>
+ _configuration.GetValue(ImagingPrefix+"AutoFillImageProperties",
+ DefaultImagingAutoFillUploadField);
+
+
+ public bool ResolveUrlsFromTextString =>
+ _configuration.GetValue(Prefix+"ResolveUrlsFromTextString", false);
+
+ public IEnumerable Error404Collection => _configuration
+ .GetSection(Prefix+"Errors:Error404")
+ .GetChildren()
+ .Select(x => new ContentErrorPage(x));
+
+ public string PreviewBadge => _configuration.GetValue(Prefix+"PreviewBadge", DefaultPreviewBadge);
+
+ public MacroErrorBehaviour MacroErrorBehaviour =>
+ _configuration.GetValue(Prefix+"MacroErrors", MacroErrorBehaviour.Inline);
+
+ public IEnumerable DisallowedUploadFiles => _configuration.GetValue(
+ Prefix+"DisallowedUploadFiles",
+ new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" });
+
+ public IEnumerable AllowedUploadFiles =>
+ _configuration.GetValue(Prefix+"AllowedUploadFiles", Array.Empty());
+
+ public bool ShowDeprecatedPropertyEditors =>
+ _configuration.GetValue(Prefix+"ShowDeprecatedPropertyEditors", false);
+
+ public string LoginBackgroundImage =>
+ _configuration.GetValue(Prefix+"LoginBackgroundImage", string.Empty);
+
+ private class ContentErrorPage : IContentErrorPage
+ {
+ public ContentErrorPage(IConfigurationSection configurationSection)
+ {
+ Culture = configurationSection.Key;
+
+ var value = configurationSection.Value;
+
+ if (int.TryParse(value, out var contentId))
+ {
+ HasContentId = true;
+ ContentId = contentId;
+ }
+ else if (Guid.TryParse(value, out var contentKey))
+ {
+ HasContentKey = true;
+ ContentKey = contentKey;
+ }
+ else
+ {
+ ContentXPath = value;
+ }
+ }
+
+ public int ContentId { get; }
+ public Guid ContentKey { get; }
+ public string ContentXPath { get; }
+ public bool HasContentId { get; }
+ public bool HasContentKey { get; }
+ public string Culture { get; set; }
+ }
+
+ private class ImagingAutoFillUploadField : IImagingAutoFillUploadField
+ {
+ public string Alias { get; set; }
+ public string WidthFieldAlias { get; set; }
+ public string HeightFieldAlias { get; set; }
+ public string LengthFieldAlias { get; set; }
+ public string ExtensionFieldAlias { get; set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/CoreDebugSettings.cs b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs
new file mode 100644
index 0000000000..6d6c0eaf0d
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class CoreDebugSettings : ICoreDebugSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Core:Debug:";
+ private readonly IConfiguration _configuration;
+
+ public CoreDebugSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool LogUncompletedScopes =>
+ _configuration.GetValue(Prefix+"LogUncompletedScopes", false);
+
+ public bool DumpOnTimeoutThreadAbort =>
+ _configuration.GetValue(Prefix+"DumpOnTimeoutThreadAbort", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs
new file mode 100644
index 0000000000..581daf9f40
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ExceptionFilterSettings : IExceptionFilterSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "ExceptionFilter:";
+ private readonly IConfiguration _configuration;
+
+ public ExceptionFilterSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool Disabled => _configuration.GetValue(Prefix+"Disabled", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
new file mode 100644
index 0000000000..4b30813bd5
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ ///
+ /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information
+ /// from web.config appsettings
+ ///
+ internal class GlobalSettings : IGlobalSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigGlobalPrefix;
+
+ 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);
+
+ // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
+ public string ConfigurationStatus
+ {
+ get => _configuration.GetValue(Prefix + "ConfigurationStatus");
+ set => throw new NotImplementedException("We should remove this and only use the value from database");
+ }
+
+ public int TimeOutInMinutes => _configuration.GetValue(Prefix + "TimeOutInMinutes", 20);
+ public string DefaultUILanguage => _configuration.GetValue(Prefix + "TimeOutInMinutes", "en-US");
+
+ public bool HideTopLevelNodeFromPath =>
+ _configuration.GetValue(Prefix + "HideTopLevelNodeFromPath", false);
+
+ public bool UseHttps => _configuration.GetValue(Prefix + "UseHttps", false);
+ public int VersionCheckPeriod => _configuration.GetValue(Prefix + "VersionCheckPeriod", 7);
+ public string UmbracoPath => _configuration.GetValue(Prefix + "UmbracoPath", "~/umbraco");
+ public string UmbracoCssPath => _configuration.GetValue(Prefix + "UmbracoCssPath", "~/css");
+
+ public string UmbracoScriptsPath =>
+ _configuration.GetValue(Prefix + "UmbracoScriptsPath", "~/scripts");
+
+ public string UmbracoMediaPath => _configuration.GetValue(Prefix + "UmbracoMediaPath", "~/media");
+
+ public bool InstallMissingDatabase =>
+ _configuration.GetValue(Prefix + "InstallMissingDatabase", false);
+
+ public bool InstallEmptyDatabase => _configuration.GetValue(Prefix + "InstallEmptyDatabase", false);
+
+ public bool DisableElectionForSingleServer =>
+ _configuration.GetValue(Prefix + "DisableElectionForSingleServer", false);
+
+ public string RegisterType => _configuration.GetValue(Prefix + "RegisterType", string.Empty);
+
+ public string DatabaseFactoryServerVersion =>
+ _configuration.GetValue(Prefix + "DatabaseFactoryServerVersion", string.Empty);
+
+ public string MainDomLock => _configuration.GetValue(Prefix + "MainDomLock", string.Empty);
+
+ public string NoNodesViewPath =>
+ _configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml");
+
+ public bool IsSmtpServerConfigured =>
+ _configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false;
+
+ public ISmtpSettings SmtpSettings =>
+ new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp"));
+
+ private class SmtpSettingsImpl : ISmtpSettings
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public SmtpSettingsImpl(IConfigurationSection configurationSection)
+ {
+ _configurationSection = configurationSection;
+ }
+
+ public string From => _configurationSection.GetValue("From");
+ public string Host => _configurationSection.GetValue("Host");
+ public int Port => _configurationSection.GetValue("Port");
+ public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation");
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs
new file mode 100644
index 0000000000..1d73051ec8
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.HealthChecks;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class HealthChecksSettings : IHealthChecksSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "HealthChecks:";
+ private readonly IConfiguration _configuration;
+
+ public HealthChecksSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public IEnumerable DisabledChecks => _configuration
+ .GetSection(Prefix+"DisabledChecks")
+ .GetChildren()
+ .Select(
+ x => new DisabledHealthCheck
+ {
+ Id = x.GetValue("Id"),
+ DisabledOn = x.GetValue("DisabledOn"),
+ DisabledBy = x.GetValue("DisabledBy")
+ });
+
+ public IHealthCheckNotificationSettings NotificationSettings =>
+ new HealthCheckNotificationSettings(
+ _configuration.GetSection(Prefix+"NotificationSettings"));
+
+ private class DisabledHealthCheck : IDisabledHealthCheck
+ {
+ public Guid Id { get; set; }
+ public DateTime DisabledOn { get; set; }
+ public int DisabledBy { get; set; }
+ }
+
+ private class HealthCheckNotificationSettings : IHealthCheckNotificationSettings
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public HealthCheckNotificationSettings(IConfigurationSection configurationSection)
+ {
+ _configurationSection = configurationSection;
+ }
+
+ public bool Enabled => _configurationSection.GetValue("Enabled", false);
+ public string FirstRunTime => _configurationSection.GetValue("FirstRunTime");
+ public int PeriodInHours => _configurationSection.GetValue("PeriodInHours", 24);
+
+ public IReadOnlyDictionary NotificationMethods => _configurationSection
+ .GetSection("NotificationMethods")
+ .GetChildren()
+ .ToDictionary(x => x.Key, x => (INotificationMethod) new NotificationMethod(x.Key, x));
+
+ public IEnumerable DisabledChecks => _configurationSection
+ .GetSection("DisabledChecks").GetChildren().Select(
+ x => new DisabledHealthCheck
+ {
+ Id = x.GetValue("Id"),
+ DisabledOn = x.GetValue("DisabledOn"),
+ DisabledBy = x.GetValue("DisabledBy")
+ });
+ }
+
+ private class NotificationMethod : INotificationMethod
+ {
+ private readonly IConfigurationSection _configurationSection;
+
+ public NotificationMethod(string alias, IConfigurationSection configurationSection)
+ {
+ Alias = alias;
+ _configurationSection = configurationSection;
+ }
+
+ public string Alias { get; }
+ public bool Enabled => _configurationSection.GetValue("Enabled", false);
+
+ public HealthCheckNotificationVerbosity Verbosity =>
+ _configurationSection.GetValue("Verbosity", HealthCheckNotificationVerbosity.Summary);
+
+ public bool FailureOnly => _configurationSection.GetValue("FailureOnly", true);
+
+ public IReadOnlyDictionary Settings => _configurationSection
+ .GetSection("Settings").GetChildren().ToDictionary(x => x.Key,
+ x => (INotificationMethodSettings) new NotificationMethodSettings(x.Key, x.Value));
+ }
+
+ private class NotificationMethodSettings : INotificationMethodSettings
+ {
+ public NotificationMethodSettings(string key, string value)
+ {
+ Key = key;
+ Value = value;
+ }
+
+ public string Key { get; }
+ public string Value { get; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/HostingSettings.cs b/src/Umbraco.Configuration/Models/HostingSettings.cs
new file mode 100644
index 0000000000..f0fbcf4cab
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/HostingSettings.cs
@@ -0,0 +1,29 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class HostingSettings : IHostingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Hosting:";
+ private readonly IConfiguration _configuration;
+
+ public HostingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ ///
+ public LocalTempStorage LocalTempStorageLocation =>
+ _configuration.GetValue(Prefix+"LocalTempStorage", LocalTempStorage.Default);
+
+ public string ApplicationVirtualPath => null;
+
+ ///
+ /// Gets a value indicating whether umbraco is running in [debug mode].
+ ///
+ /// true if [debug mode]; otherwise, false.
+ public bool DebugMode => _configuration.GetValue(Prefix+"Debug", false);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ImagingSettings.cs b/src/Umbraco.Configuration/Models/ImagingSettings.cs
new file mode 100644
index 0000000000..4a9501b2ba
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ImagingSettings.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class ImagingSettings : IImagingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Imaging:";
+ private const string CachePrefix = Prefix + "Cache:";
+ private const string ResizePrefix = Prefix + "Resize:";
+ private readonly IConfiguration _configuration;
+
+ public ImagingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int MaxBrowserCacheDays => _configuration.GetValue(CachePrefix + "MaxBrowserCacheDays", 7);
+ public int MaxCacheDays => _configuration.GetValue(CachePrefix + "MaxCacheDays", 365);
+ public uint CachedNameLength => _configuration.GetValue(CachePrefix + "CachedNameLength", (uint) 8);
+ public string CacheFolder => _configuration.GetValue(CachePrefix + "Folder", "../App_Data/Cache");
+ public int MaxResizeWidth => _configuration.GetValue(ResizePrefix + "MaxWidth", 5000);
+ public int MaxResizeHeight => _configuration.GetValue(ResizePrefix + "MaxHeight", 5000);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs
new file mode 100644
index 0000000000..b4bb000552
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class IndexCreatorSettings : IIndexCreatorSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Examine:";
+ private readonly IConfiguration _configuration;
+
+ public IndexCreatorSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string LuceneDirectoryFactory =>
+ _configuration.GetValue(Prefix + "LuceneDirectoryFactory");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/KeepAliveSettings.cs b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs
new file mode 100644
index 0000000000..04194e1a3c
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class KeepAliveSettings : IKeepAliveSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "KeepAlive:";
+ private readonly IConfiguration _configuration;
+
+ public KeepAliveSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool DisableKeepAliveTask =>
+ _configuration.GetValue(Prefix + "DisableKeepAliveTask", false);
+
+ public string KeepAlivePingUrl => _configuration.GetValue(Prefix + "KeepAlivePingUrl",
+ "{umbracoApplicationUrl}/api/keepalive/ping");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/LoggingSettings.cs b/src/Umbraco.Configuration/Models/LoggingSettings.cs
new file mode 100644
index 0000000000..b05fe03875
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/LoggingSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class LoggingSettings : ILoggingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Logging:";
+ private readonly IConfiguration _configuration;
+
+ public LoggingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int MaxLogAge => _configuration.GetValue(Prefix + "MaxLogAge", -1);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..c7b147349e
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs
@@ -0,0 +1,38 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class MemberPasswordConfigurationSettings : IMemberPasswordConfiguration
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "MemberPassword:";
+ private readonly IConfiguration _configuration;
+
+ public MemberPasswordConfigurationSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int RequiredLength =>
+ _configuration.GetValue(Prefix + "RequiredLength", 10);
+
+ public bool RequireNonLetterOrDigit =>
+ _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false);
+
+ public bool RequireDigit =>
+ _configuration.GetValue(Prefix + "RequireDigit", false);
+
+ public bool RequireLowercase =>
+ _configuration.GetValue(Prefix + "RequireLowercase", false);
+
+ public bool RequireUppercase =>
+ _configuration.GetValue(Prefix + "RequireUppercase", false);
+
+ public string HashAlgorithmType =>
+ _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256");
+
+ public int MaxFailedAccessAttemptsBeforeLockout =>
+ _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs
new file mode 100644
index 0000000000..d111dbba70
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs
@@ -0,0 +1,86 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ ///
+ /// Represents the models builder configuration.
+ ///
+ internal class ModelsBuilderConfig : IModelsBuilderConfig
+ {
+ private const string Prefix = Constants.Configuration.ConfigModelsBuilderPrefix;
+ private readonly IConfiguration _configuration;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ModelsBuilderConfig(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string DefaultModelsDirectory => "~/App_Data/Models";
+
+ ///
+ /// Gets a value indicating whether the whole models experience is enabled.
+ ///
+ ///
+ /// If this is false then absolutely nothing happens.
+ /// Default value is false which means that unless we have this setting, nothing happens.
+ ///
+ public bool Enable => _configuration.GetValue(Prefix+"Enable", false);
+
+ ///
+ /// Gets the models mode.
+ ///
+ public ModelsMode ModelsMode =>
+ _configuration.GetValue(Prefix+"ModelsMode", ModelsMode.Nothing);
+
+ ///
+ /// Gets the models namespace.
+ ///
+ /// That value could be overriden by other (attribute in user's code...). Return default if no value was supplied.
+ public string ModelsNamespace => _configuration.GetValue(Prefix+"ModelsNamespace");
+
+ ///
+ /// Gets a value indicating whether we should enable the models factory.
+ ///
+ /// Default value is true because no factory is enabled by default in Umbraco.
+ public bool EnableFactory => _configuration.GetValue(Prefix+"EnableFactory", true);
+
+ ///
+ /// Gets a value indicating whether we should flag out-of-date models.
+ ///
+ ///
+ /// Models become out-of-date when data types or content types are updated. When this
+ /// setting is activated the ~/App_Data/Models/ood.txt file is then created. When models are
+ /// generated through the dashboard, the files is cleared. Default value is false.
+ ///
+ public bool FlagOutOfDateModels =>
+ _configuration.GetValue(Prefix+"FlagOutOfDateModels", false) && !ModelsMode.IsLive();
+
+ ///
+ /// Gets the models directory.
+ ///
+ /// Default is ~/App_Data/Models but that can be changed.
+ public string ModelsDirectory =>
+ _configuration.GetValue(Prefix+"ModelsDirectory", "~/App_Data/Models");
+
+ ///
+ /// Gets a value indicating whether to accept an unsafe value for ModelsDirectory.
+ ///
+ ///
+ /// An unsafe value is an absolute path, or a relative path pointing outside
+ /// of the website root.
+ ///
+ public bool AcceptUnsafeModelsDirectory =>
+ _configuration.GetValue(Prefix+"AcceptUnsafeModelsDirectory", false);
+
+ ///
+ /// Gets a value indicating the debug log level.
+ ///
+ /// 0 means minimal (safe on live site), anything else means more and more details (maybe not safe).
+ public int DebugLevel => _configuration.GetValue(Prefix+"DebugLevel", 0);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/NuCacheSettings.cs b/src/Umbraco.Configuration/Models/NuCacheSettings.cs
new file mode 100644
index 0000000000..51b8b1fe08
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/NuCacheSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class NuCacheSettings : INuCacheSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "NuCache:";
+ private readonly IConfiguration _configuration;
+
+ public NuCacheSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string BTreeBlockSize => _configuration.GetValue(Prefix+"BTreeBlockSize");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs
new file mode 100644
index 0000000000..ce5cd65c20
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class RequestHandlerSettings : IRequestHandlerSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "RequestHandler:";
+ private static readonly CharItem[] DefaultCharCollection =
+ {
+ new CharItem { Char = " ", Replacement = "-" },
+ new CharItem { Char = "\"", Replacement = "" },
+ new CharItem { Char = "'", Replacement = "" },
+ new CharItem { Char = "%", Replacement = "" },
+ new CharItem { Char = ".", Replacement = "" },
+ new CharItem { Char = ";", Replacement = "" },
+ new CharItem { Char = "/", Replacement = "" },
+ new CharItem { Char = "\\", Replacement = "" },
+ new CharItem { Char = ":", Replacement = "" },
+ new CharItem { Char = "#", Replacement = "" },
+ new CharItem { Char = "+", Replacement = "plus" },
+ new CharItem { Char = "*", Replacement = "star" },
+ new CharItem { Char = "&", Replacement = "" },
+ new CharItem { Char = "?", Replacement = "" },
+ new CharItem { Char = "æ", Replacement = "ae" },
+ new CharItem { Char = "ä", Replacement = "ae" },
+ new CharItem { Char = "ø", Replacement = "oe" },
+ new CharItem { Char = "ö", Replacement = "oe" },
+ new CharItem { Char = "å", Replacement = "aa" },
+ new CharItem { Char = "ü", Replacement = "ue" },
+ new CharItem { Char = "ß", Replacement = "ss" },
+ new CharItem { Char = "|", Replacement = "-" },
+ new CharItem { Char = "<", Replacement = "" },
+ new CharItem { Char = ">", Replacement = "" }
+ };
+
+ private readonly IConfiguration _configuration;
+
+ public RequestHandlerSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool AddTrailingSlash =>
+ _configuration.GetValue(Prefix+"AddTrailingSlash", true);
+
+ public bool ConvertUrlsToAscii => _configuration
+ .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("true");
+
+ public bool TryConvertUrlsToAscii => _configuration
+ .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("try");
+
+
+ //We need to special handle ":", as this character is special in keys
+ public IEnumerable CharCollection
+ {
+ get
+ {
+ var collection = _configuration.GetSection(Prefix + "CharCollection").GetChildren()
+ .Select(x => new CharItem()
+ {
+ Char = x.GetValue("Char"),
+ Replacement = x.GetValue("Replacement"),
+ }).ToArray();
+
+ if (collection.Any() || _configuration.GetSection("Prefix").GetChildren().Any(x =>
+ x.Key.Equals("CharCollection", StringComparison.OrdinalIgnoreCase)))
+ {
+ return collection;
+ }
+
+ return DefaultCharCollection;
+ }
+ }
+
+
+ public class CharItem : IChar
+ {
+ public string Char { get; set; }
+ public string Replacement { get; set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Configuration/Models/RuntimeSettings.cs
new file mode 100644
index 0000000000..ef129030b6
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/RuntimeSettings.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class RuntimeSettings : IRuntimeSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Runtime:";
+ private readonly IConfiguration _configuration;
+ public RuntimeSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int? MaxQueryStringLength => _configuration.GetValue(Prefix+"MaxRequestLength");
+ public int? MaxRequestLength => _configuration.GetValue(Prefix+"MaxRequestLength");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/SecuritySettings.cs b/src/Umbraco.Configuration/Models/SecuritySettings.cs
new file mode 100644
index 0000000000..9244eace96
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/SecuritySettings.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class SecuritySettings : ISecuritySettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix;
+ private readonly IConfiguration _configuration;
+
+ public SecuritySettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool KeepUserLoggedIn => _configuration.GetValue(Prefix + "KeepUserLoggedIn", true);
+
+ public bool HideDisabledUsersInBackoffice =>
+ _configuration.GetValue(Prefix + "HideDisabledUsersInBackoffice", false);
+
+ public bool AllowPasswordReset =>
+ _configuration.GetValue(Prefix + "AllowPasswordResetAllowPasswordReset", true);
+
+ public string AuthCookieName =>
+ _configuration.GetValue(Prefix + "AuthCookieName", "UMB_UCONTEXT");
+
+ public string AuthCookieDomain =>
+ _configuration.GetValue(Prefix + "AuthCookieDomain");
+
+ public bool UsernameIsEmail => _configuration.GetValue(Prefix + "UsernameIsEmail", true);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/TourSettings.cs b/src/Umbraco.Configuration/Models/TourSettings.cs
new file mode 100644
index 0000000000..9fe1814ff5
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/TourSettings.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class TourSettings : ITourSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "Tours:";
+ private readonly IConfiguration _configuration;
+
+ public TourSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string Type { get; set; }
+
+ public bool EnableTours => _configuration.GetValue(Prefix+"EnableTours", true);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/TypeFinderSettings.cs b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs
new file mode 100644
index 0000000000..8a1f7ac9e0
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class TypeFinderSettings : ITypeFinderSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "TypeFinder:";
+ private readonly IConfiguration _configuration;
+
+ public TypeFinderSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public string AssembliesAcceptingLoadExceptions =>
+ _configuration.GetValue(Prefix+"AssembliesAcceptingLoadExceptions");
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs
new file mode 100644
index 0000000000..5e68b16203
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs
@@ -0,0 +1,36 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class UserPasswordConfigurationSettings : IUserPasswordConfiguration
+ {
+ private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "UserPassword:";
+ private readonly IConfiguration _configuration;
+
+ public UserPasswordConfigurationSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public int RequiredLength => _configuration.GetValue(Prefix + "RequiredLength", 10);
+
+ public bool RequireNonLetterOrDigit =>
+ _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false);
+
+ public bool RequireDigit => _configuration.GetValue(Prefix + "RequireDigit", false);
+
+ public bool RequireLowercase =>
+ _configuration.GetValue(Prefix + "RequireLowercase", false);
+
+ public bool RequireUppercase =>
+ _configuration.GetValue(Prefix + "RequireUppercase", false);
+
+ public string HashAlgorithmType =>
+ _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256");
+
+ public int MaxFailedAccessAttemptsBeforeLockout =>
+ _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5);
+ }
+}
diff --git a/src/Umbraco.Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs
new file mode 100644
index 0000000000..9ac856ca9f
--- /dev/null
+++ b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Models.PublishedContent;
+
+namespace Umbraco.Configuration.Models
+{
+ internal class WebRoutingSettings : IWebRoutingSettings
+ {
+ private const string Prefix = Constants.Configuration.ConfigPrefix + "WebRouting:";
+ private readonly IConfiguration _configuration;
+
+ public WebRoutingSettings(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public bool TrySkipIisCustomErrors =>
+ _configuration.GetValue(Prefix + "TrySkipIisCustomErrors", false);
+
+ public bool InternalRedirectPreservesTemplate =>
+ _configuration.GetValue(Prefix + "InternalRedirectPreservesTemplate", false);
+
+ public bool DisableAlternativeTemplates =>
+ _configuration.GetValue(Prefix + "DisableAlternativeTemplates", false);
+
+ public bool ValidateAlternativeTemplates =>
+ _configuration.GetValue(Prefix + "ValidateAlternativeTemplates", false);
+
+ public bool DisableFindContentByIdPath =>
+ _configuration.GetValue(Prefix + "DisableFindContentByIdPath", false);
+
+ public bool DisableRedirectUrlTracking =>
+ _configuration.GetValue(Prefix + "DisableRedirectUrlTracking", false);
+
+ public string UrlProviderMode =>
+ _configuration.GetValue(Prefix + "UrlProviderMode", UrlMode.Auto.ToString());
+
+ public string UmbracoApplicationUrl =>
+ _configuration.GetValue(Prefix + "UmbracoApplicationUrl");
+ }
+}
diff --git a/src/Umbraco.Configuration/Properties/AssemblyInfo.cs b/src/Umbraco.Configuration/Properties/AssemblyInfo.cs
index d10dd929da..b77c087e22 100644
--- a/src/Umbraco.Configuration/Properties/AssemblyInfo.cs
+++ b/src/Umbraco.Configuration/Properties/AssemblyInfo.cs
@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
// Umbraco Cms
[assembly: InternalsVisibleTo("Umbraco.Tests")]
+[assembly: InternalsVisibleTo("Umbraco.Tests.Common")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")]
// Allow this to be mocked in our unit tests
diff --git a/src/Umbraco.Configuration/Umbraco.Configuration.csproj b/src/Umbraco.Configuration/Umbraco.Configuration.csproj
index 57fca1dfd6..2337ea24f8 100644
--- a/src/Umbraco.Configuration/Umbraco.Configuration.csproj
+++ b/src/Umbraco.Configuration/Umbraco.Configuration.csproj
@@ -22,6 +22,9 @@
+
+
+
@@ -29,4 +32,10 @@
+
+
+ <_Parameter1>Umbraco.Tests.Integration
+
+
+
diff --git a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs b/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs
index 79bff51d05..46b9bf32a9 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs
@@ -7,6 +7,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("tours")]
internal TourConfigElement Tours => (TourConfigElement)this["tours"];
- ITourSection IBackOfficeSection.Tours => Tours;
+ ITourSettings IBackOfficeSection.Tours => Tours;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs
index 8e4f0edd8f..28b4314c9a 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs
@@ -4,7 +4,7 @@ using Umbraco.Core.Macros;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class ContentElement : UmbracoConfigurationElement, IContentSection
+ internal class ContentElement : UmbracoConfigurationElement, IContentSettings
{
private const string DefaultPreviewBadge = @"";
@@ -40,26 +40,26 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("loginBackgroundImage")]
internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty);
- string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress;
+ string IContentSettings.NotificationEmailAddress => Notifications.NotificationEmailAddress;
- bool IContentSection.DisableHtmlEmail => Notifications.DisableHtmlEmail;
+ bool IContentSettings.DisableHtmlEmail => Notifications.DisableHtmlEmail;
- IEnumerable IContentSection.ImageFileTypes => Imaging.ImageFileTypes;
+ IEnumerable IContentSettings.ImageFileTypes => Imaging.ImageFileTypes;
- IEnumerable IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
+ IEnumerable IContentSettings.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
- bool IContentSection.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
+ bool IContentSettings.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
- string IContentSection.PreviewBadge => PreviewBadge;
+ string IContentSettings.PreviewBadge => PreviewBadge;
- MacroErrorBehaviour IContentSection.MacroErrorBehaviour => MacroErrors;
+ MacroErrorBehaviour IContentSettings.MacroErrorBehaviour => MacroErrors;
- IEnumerable IContentSection.DisallowedUploadFiles => DisallowedUploadFiles;
+ IEnumerable IContentSettings.DisallowedUploadFiles => DisallowedUploadFiles;
- IEnumerable IContentSection.AllowedUploadFiles => AllowedUploadFiles;
+ IEnumerable IContentSettings.AllowedUploadFiles => AllowedUploadFiles;
- bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
+ bool IContentSettings.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
- string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
+ string IContentSettings.LoginBackgroundImage => LoginBackgroundImage;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs b/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs
index 89ba9be54d..2297fb4e20 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class KeepAliveElement : ConfigurationElement, IKeepAliveSection
+ internal class KeepAliveElement : ConfigurationElement, IKeepAliveSettings
{
[ConfigurationProperty("disableKeepAliveTask", DefaultValue = "false")]
public bool DisableKeepAliveTask => (bool)base["disableKeepAliveTask"];
diff --git a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs
index 106b6cc134..2fdd61e169 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs
@@ -3,12 +3,12 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class LoggingElement : UmbracoConfigurationElement, ILoggingSection
+ internal class LoggingElement : UmbracoConfigurationElement, ILoggingSettings
{
[ConfigurationProperty("maxLogAge")]
internal InnerTextConfigurationElement MaxLogAge => GetOptionalTextElement("maxLogAge", -1);
- int ILoggingSection.MaxLogAge => MaxLogAge;
+ int ILoggingSettings.MaxLogAge => MaxLogAge;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs
index 93c7c20159..92cd112630 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfigurationSection
+ internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfiguration
{
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs b/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs
index 80fcb6ca1a..f959a56e71 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSection
+ internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSettings
{
[ConfigurationProperty("addTrailingSlash")]
public InnerTextConfigurationElement AddTrailingSlash => GetOptionalTextElement("addTrailingSlash", true);
@@ -85,12 +85,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
return collection;
}
- bool IRequestHandlerSection.AddTrailingSlash => AddTrailingSlash;
+ bool IRequestHandlerSettings.AddTrailingSlash => AddTrailingSlash;
- bool IRequestHandlerSection.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
+ bool IRequestHandlerSettings.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
- bool IRequestHandlerSection.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
+ bool IRequestHandlerSettings.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
- IEnumerable IRequestHandlerSection.CharCollection => UrlReplacing.CharCollection;
+ IEnumerable IRequestHandlerSettings.CharCollection => UrlReplacing.CharCollection;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs b/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs
index 82012cfd0f..aec6809298 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class SecurityElement : UmbracoConfigurationElement, ISecuritySection
+ internal class SecurityElement : UmbracoConfigurationElement, ISecuritySettings
{
[ConfigurationProperty("keepUserLoggedIn")]
internal InnerTextConfigurationElement KeepUserLoggedIn => GetOptionalTextElement("keepUserLoggedIn", true);
@@ -38,14 +38,14 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("memberPasswordConfiguration")]
public MemberPasswordConfigurationElement MemberPasswordConfiguration => (MemberPasswordConfigurationElement)this["memberPasswordConfiguration"];
- bool ISecuritySection.KeepUserLoggedIn => KeepUserLoggedIn;
+ bool ISecuritySettings.KeepUserLoggedIn => KeepUserLoggedIn;
- bool ISecuritySection.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice;
+ bool ISecuritySettings.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice;
///
/// Used to enable/disable the forgot password functionality on the back office login screen
///
- bool ISecuritySection.AllowPasswordReset => AllowPasswordReset;
+ bool ISecuritySettings.AllowPasswordReset => AllowPasswordReset;
///
/// A boolean indicating that by default the email address will be the username
@@ -54,14 +54,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
/// Even if this is true and the username is different from the email in the database, the username field will still be shown.
/// When this is false, the username and email fields will be shown in the user section.
///
- bool ISecuritySection.UsernameIsEmail => UsernameIsEmail;
+ bool ISecuritySettings.UsernameIsEmail => UsernameIsEmail;
- string ISecuritySection.AuthCookieName => AuthCookieName;
+ string ISecuritySettings.AuthCookieName => AuthCookieName;
- string ISecuritySection.AuthCookieDomain => AuthCookieDomain;
-
- IUserPasswordConfigurationSection ISecuritySection.UserPasswordConfiguration => UserPasswordConfiguration;
-
- IMemberPasswordConfigurationSection ISecuritySection.MemberPasswordConfiguration => MemberPasswordConfiguration;
+ string ISecuritySettings.AuthCookieDomain => AuthCookieDomain;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs b/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs
index dab69f3da0..f75b71fc57 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class TourConfigElement : UmbracoConfigurationElement, ITourSection
+ internal class TourConfigElement : UmbracoConfigurationElement, ITourSettings
{
//disabled by default so that upgraders don't get it enabled by default
// TODO: we probably just want to disable the initial one from automatically loading ?
diff --git a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs b/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs
index e605b86edf..781d00b979 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
+ internal class UmbracoSettingsSection : ConfigurationSection
{
[ConfigurationProperty("backOffice")]
public BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"];
@@ -24,19 +24,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("keepAlive")]
internal KeepAliveElement KeepAlive => (KeepAliveElement)this["keepAlive"];
-
- IContentSection IUmbracoSettingsSection.Content => Content;
-
- ISecuritySection IUmbracoSettingsSection.Security => Security;
-
- IRequestHandlerSection IUmbracoSettingsSection.RequestHandler => RequestHandler;
-
- IBackOfficeSection IUmbracoSettingsSection.BackOffice => BackOffice;
-
- ILoggingSection IUmbracoSettingsSection.Logging => Logging;
-
- IWebRoutingSection IUmbracoSettingsSection.WebRouting => WebRouting;
-
- IKeepAliveSection IUmbracoSettingsSection.KeepAlive => KeepAlive;
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs
index 8128f3d8e7..a1d2aa8842 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfigurationSection
+ internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfiguration
{
}
}
diff --git a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs
index 7b7102f2e7..206fc213d2 100644
--- a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs
+++ b/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class WebRoutingElement : ConfigurationElement, IWebRoutingSection
+ internal class WebRoutingElement : ConfigurationElement, IWebRoutingSettings
{
[ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")]
public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"];
diff --git a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs b/src/Umbraco.Configuration/UmbracoVersionExtensions.cs
deleted file mode 100644
index 168bb16f57..0000000000
--- a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Configuration;
-using Semver;
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-
-namespace Umbraco.Configuration
-{
- public static class UmbracoVersionExtensions
- {
- ///
- /// Gets the "local" version of the site.
- ///
- ///
- /// Three things have a version, really: the executing code, the database model,
- /// and the site/files. The database model version is entirely managed via migrations,
- /// and changes during an upgrade. The executing code version changes when new code is
- /// deployed. The site/files version changes during an upgrade.
- ///
- public static SemVersion LocalVersion(this IUmbracoVersion umbracoVersion)
- {
- try
- {
- // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
- var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus];
- return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
- }
- catch
- {
- return null;
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Actions/ActionCollectionBuilder.cs b/src/Umbraco.Core/Actions/ActionCollectionBuilder.cs
index ec1a9210a7..eaea63b3a3 100644
--- a/src/Umbraco.Core/Actions/ActionCollectionBuilder.cs
+++ b/src/Umbraco.Core/Actions/ActionCollectionBuilder.cs
@@ -4,7 +4,7 @@ using System.Linq;
using Umbraco.Core.Composing;
namespace Umbraco.Web.Actions
{
- internal class ActionCollectionBuilder : LazyCollectionBuilderBase
+ public class ActionCollectionBuilder : LazyCollectionBuilderBase
{
protected override ActionCollectionBuilder This => this;
diff --git a/src/Umbraco.Core/AssemblyExtensions.cs b/src/Umbraco.Core/AssemblyExtensions.cs
index 0d0115ce20..19162e5934 100644
--- a/src/Umbraco.Core/AssemblyExtensions.cs
+++ b/src/Umbraco.Core/AssemblyExtensions.cs
@@ -6,6 +6,35 @@ namespace Umbraco.Core
{
public static class AssemblyExtensions
{
+ private static string _rootDir = "";
+
+ ///
+ /// Utility method that returns the path to the root of the application, by getting the path to where the assembly where this
+ /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
+ /// even if the assembly is in a /bin/debug or /bin/release folder
+ ///
+ ///
+ public static string GetRootDirectorySafe(this Assembly executingAssembly)
+ {
+ if (string.IsNullOrEmpty(_rootDir) == false)
+ {
+ return _rootDir;
+ }
+
+ var codeBase = executingAssembly.CodeBase;
+ var uri = new Uri(codeBase);
+ var path = uri.LocalPath;
+ var baseDirectory = Path.GetDirectoryName(path);
+ if (string.IsNullOrEmpty(baseDirectory))
+ throw new Exception("No root directory could be resolved. Please ensure that your Umbraco solution is correctly configured.");
+
+ _rootDir = baseDirectory.Contains("bin")
+ ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
+ : baseDirectory;
+
+ return _rootDir;
+ }
+
///
/// Returns the file used to load the assembly
///
diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
index 452f897372..e70b40160e 100644
--- a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
+++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs
@@ -73,7 +73,7 @@ namespace Umbraco.Core.Cache
var result = SafeLazy.GetSafeLazy(factory);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
// do not store null values (backward compat), clone / reset to go into the cache
- return value == null ? null : CheckCloneableAndTracksChanges(value);
+ return value == null ? null : CheckCloneableAndTracksChanges(value);
// clone / reset to go into the cache
}, timeout, isSliding, dependentFiles);
@@ -107,9 +107,9 @@ namespace Umbraco.Core.Cache
}
///
- public void ClearOfType(string typeName)
+ public void ClearOfType(Type type)
{
- InnerCache.ClearOfType(typeName);
+ InnerCache.ClearOfType(type);
}
///
diff --git a/src/Umbraco.Core/Cache/DictionaryAppCache.cs b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
index d372916240..04ee3e0afa 100644
--- a/src/Umbraco.Core/Cache/DictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/DictionaryAppCache.cs
@@ -71,16 +71,16 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType().ToString().InvariantEquals(typeName));
+ _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == type);
}
///
public virtual void ClearOfType()
{
var typeOfT = typeof(T);
- _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT);
+ ClearOfType(typeOfT);
}
///
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
index 159f9cd7cb..54009af465 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs
@@ -12,12 +12,6 @@ namespace Umbraco.Core.Cache
///
public class FastDictionaryAppCache : IAppCache
{
- private readonly ITypeFinder _typeFinder;
-
- public FastDictionaryAppCache(ITypeFinder typeFinder)
- {
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- }
///
/// Gets the internal items dictionary, for tests only!
@@ -83,9 +77,8 @@ namespace Umbraco.Core.Cache
}
///
- public void ClearOfType(string typeName)
+ public void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
index f417c5ffd0..bb55762826 100644
--- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
+++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs
@@ -12,13 +12,6 @@ namespace Umbraco.Core.Cache
///
public abstract class FastDictionaryAppCacheBase : IAppCache
{
- private readonly ITypeFinder _typeFinder;
-
- protected FastDictionaryAppCacheBase(ITypeFinder typeFinder)
- {
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- }
-
// prefix cache keys so we know which one are ours
protected const string CacheItemPrefix = "umbrtmche";
@@ -121,9 +114,8 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
index e698d93ebe..6ce43a7bc9 100644
--- a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
+++ b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache
///
/// Initializes a new instance of the class with a context, for unit tests!
///
- public HttpRequestAppCache(Func requestItems, ITypeFinder typeFinder) : base(typeFinder)
+ public HttpRequestAppCache(Func requestItems) : base()
{
ContextItems = requestItems;
}
diff --git a/src/Umbraco.Core/Cache/IAppCache.cs b/src/Umbraco.Core/Cache/IAppCache.cs
index 674781f6d6..c84ec1135c 100644
--- a/src/Umbraco.Core/Cache/IAppCache.cs
+++ b/src/Umbraco.Core/Cache/IAppCache.cs
@@ -51,14 +51,14 @@ namespace Umbraco.Core.Cache
///
/// Removes items of a specified type from the cache.
///
- /// The name of the type to remove.
+ /// The type to remove.
///
/// If the type is an interface, then all items of a type implementing that interface are
/// removed. Otherwise, only items of that exact type are removed (items of type inheriting from
/// the specified type are not removed).
/// Performs a case-sensitive search.
///
- void ClearOfType(string typeName);
+ void ClearOfType(Type type);
///
/// Removes items of a specified type from the cache.
diff --git a/src/Umbraco.Core/Cache/MacroCacheRefresher.cs b/src/Umbraco.Core/Cache/MacroCacheRefresher.cs
index 0863577487..009e9f38d0 100644
--- a/src/Umbraco.Core/Cache/MacroCacheRefresher.cs
+++ b/src/Umbraco.Core/Cache/MacroCacheRefresher.cs
@@ -53,7 +53,7 @@ namespace Umbraco.Web.Cache
{
macroRepoCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id));
}
- };
+ }
base.Refresh(json);
}
diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs
index 60bc6fb8b8..cae3a7381e 100644
--- a/src/Umbraco.Core/Cache/NoAppCache.cs
+++ b/src/Umbraco.Core/Cache/NoAppCache.cs
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Cache
{ }
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{ }
///
diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
index 208390276a..dc9163affb 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs
@@ -13,15 +13,13 @@ namespace Umbraco.Core.Cache
///
public class ObjectCacheAppCache : IAppPolicyCache
{
- private readonly ITypeFinder _typeFinder;
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
///
/// Initializes a new instance of the .
///
- public ObjectCacheAppCache(ITypeFinder typeFinder)
+ public ObjectCacheAppCache()
{
- _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
// the MemoryCache is created with name "in-memory". That name is
// used to retrieve configuration options. It does not identify the memory cache, i.e.
// each instance of this class has its own, independent, memory cache.
@@ -178,9 +176,8 @@ namespace Umbraco.Core.Cache
}
///
- public virtual void ClearOfType(string typeName)
+ public virtual void ClearOfType(Type type)
{
- var type = _typeFinder.GetTypeByName(typeName);
if (type == null) return;
var isInterface = type.IsInterface;
try
diff --git a/src/Umbraco.Core/Collections/TopoGraph.cs b/src/Umbraco.Core/Collections/TopoGraph.cs
index b8ded4a458..955a210465 100644
--- a/src/Umbraco.Core/Collections/TopoGraph.cs
+++ b/src/Umbraco.Core/Collections/TopoGraph.cs
@@ -126,7 +126,7 @@ namespace Umbraco.Core.Collections
if (_items.TryGetValue(key, out value))
yield return value;
else if (throwOnMissing)
- throw new Exception(MissingDependencyError);
+ throw new Exception($"{MissingDependencyError} Error in type {typeof(TItem).Name}, with key {key}");
}
}
}
diff --git a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
index 41038ea4e9..0d398be83b 100644
--- a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
+++ b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs
@@ -79,9 +79,12 @@ namespace Umbraco.Core.Composing
foreach (var type in types)
EnsureType(type, "register");
- // register them
+ // register them - ensuring that each item is registered with the same lifetime as the collection.
+ // NOTE: Previously each one was not registered with the same lifetime which would mean that if there
+ // was a dependency on an individual item, it would resolve a brand new transient instance which isn't what
+ // we would expect to happen. The same item should be resolved from the container as the collection.
foreach (var type in types)
- register.Register(type);
+ register.Register(type, CollectionLifetime);
_registeredTypes = types;
}
diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs
index a186a1f00a..f6e8655575 100644
--- a/src/Umbraco.Core/Composing/Composition.cs
+++ b/src/Umbraco.Core/Composing/Composition.cs
@@ -31,15 +31,16 @@ namespace Umbraco.Core.Composing
/// The runtime state.
/// Optional configs.
/// An IOHelper
+ ///
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs, IIOHelper ioHelper, AppCaches appCaches)
{
- _register = register;
- TypeLoader = typeLoader;
- Logger = logger;
- RuntimeState = runtimeState;
- Configs = configs;
- IOHelper = ioHelper;
- AppCaches = appCaches;
+ _register = register ?? throw new ArgumentNullException(nameof(register));
+ TypeLoader = typeLoader ?? throw new ArgumentNullException(nameof(typeLoader));
+ Logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ RuntimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
+ Configs = configs ?? throw new ArgumentNullException(nameof(configs));
+ IOHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
+ AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches));
}
#region Services
@@ -135,7 +136,7 @@ namespace Umbraco.Core.Composing
IFactory factory = null;
- Configs.RegisterWith(_register, () => factory);
+ Configs.RegisterWith(_register);
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
new file mode 100644
index 0000000000..4d153d8922
--- /dev/null
+++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Returns a list of scannable assemblies based on an entry point assembly and it's references
+ ///
+ ///
+ /// This will recursively search through the entry point's assemblies and Umbraco's core assemblies and their references
+ /// to create a list of scannable assemblies based on whether they themselves or their transitive dependencies reference Umbraco core assemblies.
+ ///
+ public class DefaultUmbracoAssemblyProvider : IAssemblyProvider
+ {
+ private readonly Assembly _entryPointAssembly;
+ private static readonly string[] UmbracoCoreAssemblyNames = new[]
+ {
+ "Umbraco.Core",
+ "Umbraco.Web",
+ "Umbraco.Infrastructure",
+ "Umbraco.PublishedCache.NuCache",
+ "Umbraco.ModelsBuilder.Embedded",
+ "Umbraco.Examine.Lucene",
+ "Umbraco.Web.Common",
+ "Umbraco.Web.BackOffice",
+ "Umbraco.Web.Website",
+ };
+
+ public DefaultUmbracoAssemblyProvider(Assembly entryPointAssembly)
+ {
+ _entryPointAssembly = entryPointAssembly ?? throw new ArgumentNullException(nameof(entryPointAssembly));
+ }
+
+ // TODO: It would be worth investigating a netcore3 version of this which would use
+ // var allAssemblies = System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies);
+ // that will still only resolve Assemblies that are already loaded but it would also make it possible to
+ // query dynamically generated assemblies once they are added. It would also provide the ability to probe
+ // assembly locations that are not in the same place as the entry point assemblies.
+
+ public IEnumerable Assemblies
+ {
+ get
+ {
+ var finder = new FindAssembliesWithReferencesTo(new[] { _entryPointAssembly }, UmbracoCoreAssemblyNames, true);
+ return finder.Find();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/DisableAttribute.cs b/src/Umbraco.Core/Composing/DisableAttribute.cs
index c2a419f8bc..e826f1c472 100644
--- a/src/Umbraco.Core/Composing/DisableAttribute.cs
+++ b/src/Umbraco.Core/Composing/DisableAttribute.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reflection;
namespace Umbraco.Core.Composing
{
@@ -21,6 +22,11 @@ namespace Umbraco.Core.Composing
public DisableAttribute()
{ }
+ public DisableAttribute(string fullTypeName, string assemblyName)
+ {
+ DisabledType = Assembly.Load(assemblyName)?.GetType(fullTypeName);
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
new file mode 100644
index 0000000000..9378941166
--- /dev/null
+++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Finds Assemblies from the entry point assemblies, it's dependencies and it's transitive dependencies that reference that targetAssemblyNames
+ ///
+ ///
+ /// borrowed and modified from here https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/FindAssembliesWithReferencesTo.cs
+ ///
+ internal class FindAssembliesWithReferencesTo
+ {
+ private readonly Assembly[] _referenceAssemblies;
+ private readonly string[] _targetAssemblies;
+ private readonly bool _includeTargets;
+
+ ///
+ /// Constructor
+ ///
+ /// Entry point assemblies
+ /// Used to check if the entry point or it's transitive assemblies reference these assembly names
+ /// If true will also use the target assembly names as entry point assemblies
+ public FindAssembliesWithReferencesTo(Assembly[] referenceAssemblies, string[] targetAssemblyNames, bool includeTargets)
+ {
+ _referenceAssemblies = referenceAssemblies;
+ _targetAssemblies = targetAssemblyNames;
+ _includeTargets = includeTargets;
+ }
+
+ public IEnumerable Find()
+ {
+ var referenceItems = new List();
+ foreach (var assembly in _referenceAssemblies)
+ {
+ referenceItems.Add(assembly);
+ }
+
+ if (_includeTargets)
+ {
+ foreach(var target in _targetAssemblies)
+ {
+ try
+ {
+ referenceItems.Add(Assembly.Load(target));
+ }
+ catch (FileNotFoundException)
+ {
+ // occurs if we cannot load this ... for example in a test project where we aren't currently referencing Umbraco.Web, etc...
+ }
+ }
+ }
+
+ var provider = new ReferenceResolver(_targetAssemblies, referenceItems);
+ var assemblyNames = provider.ResolveAssemblies();
+ return assemblyNames.ToList();
+ }
+
+ }
+}
diff --git a/src/Umbraco.Core/Composing/IAssemblyProvider.cs b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
new file mode 100644
index 0000000000..bde97a9556
--- /dev/null
+++ b/src/Umbraco.Core/Composing/IAssemblyProvider.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Provides a list of assemblies that can be scanned
+ ///
+ public interface IAssemblyProvider
+ {
+ IEnumerable Assemblies { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/IRuntimeHash.cs b/src/Umbraco.Core/Composing/IRuntimeHash.cs
new file mode 100644
index 0000000000..c2fb829cc6
--- /dev/null
+++ b/src/Umbraco.Core/Composing/IRuntimeHash.cs
@@ -0,0 +1,14 @@
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Used to create a hash value of the current runtime
+ ///
+ ///
+ /// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
+ /// part of the application has changed. This is used to detect if we need to re-type scan.
+ ///
+ public interface IRuntimeHash
+ {
+ string GetHashValue();
+ }
+}
diff --git a/src/Umbraco.Core/Composing/ITypeFinder.cs b/src/Umbraco.Core/Composing/ITypeFinder.cs
index f302976dd6..7ed6084074 100644
--- a/src/Umbraco.Core/Composing/ITypeFinder.cs
+++ b/src/Umbraco.Core/Composing/ITypeFinder.cs
@@ -51,5 +51,14 @@ namespace Umbraco.Core.Composing
Type attributeType,
IEnumerable assemblies,
bool onlyConcreteClasses);
+
+ ///
+ /// Gets a hash value of the current runtime
+ ///
+ ///
+ /// This is used to detect if the runtime itself has changed, like a DLL has changed or another dynamically compiled
+ /// part of the application has changed. This is used to detect if we need to re-type scan.
+ ///
+ string GetRuntimeHash();
}
}
diff --git a/src/Umbraco.Core/Composing/ReferenceResolver.cs b/src/Umbraco.Core/Composing/ReferenceResolver.cs
new file mode 100644
index 0000000000..65dba8bf23
--- /dev/null
+++ b/src/Umbraco.Core/Composing/ReferenceResolver.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Resolves assemblies that reference one of the specified "targetAssemblies" either directly or transitively.
+ ///
+ ///
+ /// Borrowed and modified from https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/ReferenceResolver.cs
+ ///
+ internal class ReferenceResolver
+ {
+ private readonly HashSet _umbracoAssemblies;
+ private readonly IReadOnlyList _assemblies;
+ private readonly Dictionary _classifications;
+ private readonly List _lookup = new List();
+
+ public ReferenceResolver(IReadOnlyList targetAssemblies, IReadOnlyList entryPointAssemblies)
+ {
+ _umbracoAssemblies = new HashSet(targetAssemblies, StringComparer.Ordinal);
+ _assemblies = entryPointAssemblies;
+ _classifications = new Dictionary();
+
+ foreach (var item in entryPointAssemblies)
+ {
+ _lookup.Add(item);
+ }
+ }
+
+ ///
+ /// Returns a list of assemblies that directly reference or transitively reference the targetAssemblies
+ ///
+ ///
+ ///
+ /// This includes all assemblies in the same location as the entry point assemblies
+ ///
+ public IEnumerable ResolveAssemblies()
+ {
+ var applicationParts = new List();
+
+ var assemblies = new HashSet(_assemblies);
+
+ // Get the unique directories of the assemblies
+ var assemblyLocations = GetAssemblyFolders(assemblies).ToList();
+
+ // Load in each assembly in the directory of the entry assembly to be included in the search
+ // for Umbraco dependencies/transitive dependencies
+ foreach(var dir in assemblyLocations)
+ {
+ foreach(var dll in Directory.EnumerateFiles(dir, "*.dll"))
+ {
+ var assemblyName = AssemblyName.GetAssemblyName(dll);
+
+ // don't include if this is excluded
+ if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assemblyName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
+ continue;
+
+ // don't include this item if it's Umbraco
+ // TODO: We should maybe pass an explicit list of these names in?
+ if (assemblyName.FullName.StartsWith("Umbraco."))
+ continue;
+
+ var assembly = Assembly.Load(assemblyName);
+ assemblies.Add(assembly);
+ }
+ }
+
+ foreach (var item in assemblies)
+ {
+ var classification = Resolve(item);
+ if (classification == Classification.ReferencesUmbraco || classification == Classification.IsUmbraco)
+ {
+ applicationParts.Add(item);
+ }
+ }
+
+ return applicationParts;
+ }
+
+
+ private IEnumerable GetAssemblyFolders(IEnumerable assemblies)
+ {
+ return assemblies.Select(x => Path.GetDirectoryName(GetAssemblyLocation(x)).ToLowerInvariant()).Distinct();
+ }
+
+ // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs
+ private string GetAssemblyLocation(Assembly assembly)
+ {
+ if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out var result) &&
+ result.IsFile && string.IsNullOrWhiteSpace(result.Fragment))
+ {
+ return result.LocalPath;
+ }
+
+ return assembly.Location;
+ }
+
+ private Classification Resolve(Assembly assembly)
+ {
+ if (_classifications.TryGetValue(assembly, out var classification))
+ {
+ return classification;
+ }
+
+ // Initialize the dictionary with a value to short-circuit recursive references.
+ classification = Classification.Unknown;
+ _classifications[assembly] = classification;
+
+ if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assembly.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
+ {
+ // if its part of the filter it doesn't reference umbraco
+ classification = Classification.DoesNotReferenceUmbraco;
+ }
+ else if (_umbracoAssemblies.Contains(assembly.GetName().Name))
+ {
+ classification = Classification.IsUmbraco;
+ }
+ else
+ {
+ classification = Classification.DoesNotReferenceUmbraco;
+ foreach (var reference in GetReferences(assembly))
+ {
+ // recurse
+ var referenceClassification = Resolve(reference);
+
+ if (referenceClassification == Classification.IsUmbraco || referenceClassification == Classification.ReferencesUmbraco)
+ {
+ classification = Classification.ReferencesUmbraco;
+ break;
+ }
+ }
+ }
+
+ Debug.Assert(classification != Classification.Unknown);
+ _classifications[assembly] = classification;
+ return classification;
+ }
+
+ protected virtual IEnumerable GetReferences(Assembly assembly)
+ {
+ foreach (var referenceName in assembly.GetReferencedAssemblies())
+ {
+ // don't include if this is excluded
+ if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => referenceName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
+ continue;
+
+ var reference = Assembly.Load(referenceName);
+
+ if (!_lookup.Contains(reference))
+ {
+ // A dependency references an item that isn't referenced by this project.
+ // We'll add this reference so that we can calculate the classification.
+
+ _lookup.Add(reference);
+ }
+ yield return reference;
+ }
+ }
+
+ protected enum Classification
+ {
+ Unknown,
+ DoesNotReferenceUmbraco,
+ ReferencesUmbraco,
+ IsUmbraco,
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/RuntimeHash.cs b/src/Umbraco.Core/Composing/RuntimeHash.cs
new file mode 100644
index 0000000000..16665384c6
--- /dev/null
+++ b/src/Umbraco.Core/Composing/RuntimeHash.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Determines the runtime hash based on file system paths to scan
+ ///
+ public class RuntimeHash : IRuntimeHash
+ {
+ private readonly IProfilingLogger _logger;
+ private readonly RuntimeHashPaths _paths;
+
+ public RuntimeHash(IProfilingLogger logger, RuntimeHashPaths paths)
+ {
+ _logger = logger;
+ _paths = paths;
+ }
+
+
+ public string GetHashValue()
+ {
+ var allPaths = _paths.GetFolders()
+ .Select(x => ((FileSystemInfo) x, false))
+ .Concat(_paths.GetFiles().Select(x => ((FileSystemInfo) x.Key, x.Value)));
+
+ var hash = GetFileHash(allPaths);
+
+ return hash;
+ }
+
+ ///
+ /// Returns a unique hash for a combination of FileInfo objects.
+ ///
+ /// A collection of files.
+ /// The hash.
+ /// Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the
+ /// file properties (false) or the file contents (true).
+ private string GetFileHash(IEnumerable<(FileSystemInfo fileOrFolder, bool scanFileContent)> filesAndFolders)
+ {
+ using (_logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
+ {
+ // get the distinct file infos to hash
+ var uniqInfos = new HashSet();
+ var uniqContent = new HashSet();
+
+ using var generator = new HashGenerator();
+
+ foreach (var (fileOrFolder, scanFileContent) in filesAndFolders)
+ {
+ if (scanFileContent)
+ {
+ // add each unique file's contents to the hash
+ // normalize the content for cr/lf and case-sensitivity
+ if (uniqContent.Add(fileOrFolder.FullName))
+ {
+ if (File.Exists(fileOrFolder.FullName) == false) continue;
+ var content = RemoveCrLf(File.ReadAllText(fileOrFolder.FullName));
+ generator.AddCaseInsensitiveString(content);
+ }
+ }
+ else
+ {
+ // add each unique folder/file to the hash
+ if (uniqInfos.Add(fileOrFolder.FullName))
+ {
+ generator.AddFileSystemItem(fileOrFolder);
+ }
+ }
+ }
+ return generator.GenerateHash();
+ }
+ }
+
+ // fast! (yes, according to benchmarks)
+ private static string RemoveCrLf(string s)
+ {
+ var buffer = new char[s.Length];
+ var count = 0;
+ // ReSharper disable once ForCanBeConvertedToForeach - no!
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] != '\r' && s[i] != '\n')
+ buffer[count++] = s[i];
+ }
+ return new string(buffer, 0, count);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs
new file mode 100644
index 0000000000..8b5af064af
--- /dev/null
+++ b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// Paths used to determine the
+ ///
+ public sealed class RuntimeHashPaths
+ {
+ private readonly List _paths = new List();
+ private readonly Dictionary _files = new Dictionary();
+
+ public void AddFolder(DirectoryInfo pathInfo) => _paths.Add(pathInfo);
+ public void AddFile(FileInfo fileInfo, bool scanFileContent = false) => _files.Add(fileInfo, scanFileContent);
+
+ public IEnumerable GetFolders() => _paths;
+ public IReadOnlyDictionary GetFiles() => _files;
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs
index 9d88153b0a..645182d66b 100644
--- a/src/Umbraco.Core/Composing/TypeFinder.cs
+++ b/src/Umbraco.Core/Composing/TypeFinder.cs
@@ -1,106 +1,37 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Configuration;
-using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Text;
using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.Exceptions;
-using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Composing
{
+
///
public class TypeFinder : ITypeFinder
{
private readonly ILogger _logger;
-
- public TypeFinder(ILogger logger, ITypeFinderConfig typeFinderConfig = null)
- {
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty();
- _allAssemblies = new Lazy>(() =>
- {
- HashSet assemblies = null;
- try
- {
- //NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have
- // already been loaded in to the app domain, instead we will look directly into the bin folder and load each one.
- var binFolder = GetRootDirectorySafe();
- var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- //var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
- //var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
- assemblies = new HashSet();
- foreach (var a in binAssemblyFiles)
- {
- try
- {
- var assName = AssemblyName.GetAssemblyName(a);
- var ass = Assembly.Load(assName);
- assemblies.Add(ass);
- }
- catch (Exception e)
- {
- if (e is SecurityException || e is BadImageFormatException)
- {
- //swallow these exceptions
- }
- else
- {
- throw;
- }
- }
- }
-
- //Since we are only loading in the /bin assemblies above, we will also load in anything that's already loaded (which will include gac items)
- foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
- {
- assemblies.Add(a);
- }
- }
- catch (InvalidOperationException e)
- {
- if (e.InnerException is SecurityException == false)
- throw;
- }
-
- return assemblies;
- });
- }
-
- //Lazy access to the all assemblies list
- private readonly Lazy> _allAssemblies;
+ private readonly IAssemblyProvider _assemblyProvider;
+ private readonly IRuntimeHash _runtimeHash;
private volatile HashSet _localFilteredAssemblyCache;
private readonly object _localFilteredAssemblyCacheLocker = new object();
private readonly List _notifiedLoadExceptionAssemblies = new List();
- private static readonly ConcurrentDictionary TypeNamesCache= new ConcurrentDictionary();
- private string _rootDir = "";
+ private static readonly ConcurrentDictionary TypeNamesCache = new ConcurrentDictionary();
private readonly string[] _assembliesAcceptingLoadExceptions;
- // FIXME - this is only an interim change, once the IIOHelper stuff is merged we should use IIOHelper here
- private string GetRootDirectorySafe()
+ // used for benchmark tests
+ internal bool QueryWithReferencingAssemblies = true;
+
+ public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, IRuntimeHash runtimeHash, ITypeFinderConfig typeFinderConfig = null)
{
- if (string.IsNullOrEmpty(_rootDir) == false)
- {
- return _rootDir;
- }
-
- var codeBase = Assembly.GetExecutingAssembly().CodeBase;
- var uri = new Uri(codeBase);
- var path = uri.LocalPath;
- var baseDirectory = Path.GetDirectoryName(path);
- if (string.IsNullOrEmpty(baseDirectory))
- throw new PanicException("No root directory could be resolved.");
-
- _rootDir = baseDirectory.Contains("bin")
- ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
- : baseDirectory;
-
- return _rootDir;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _assemblyProvider = assemblyProvider;
+ _runtimeHash = runtimeHash;
+ _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty();
}
private bool AcceptsLoadExceptions(Assembly a)
@@ -119,22 +50,8 @@ namespace Umbraco.Core.Composing
});
}
- ///
- /// lazily load a reference to all assemblies and only local assemblies.
- /// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
- ///
- ///
- /// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
- /// loaded in the CLR, not all assemblies.
- /// See these threads:
- /// http://issues.umbraco.org/issue/U5-198
- /// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
- /// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
- ///
- private IEnumerable GetAllAssemblies()
- {
- return _allAssemblies.Value;
- }
+
+ private IEnumerable GetAllAssemblies() => _assemblyProvider.Assemblies;
///
public IEnumerable AssembliesToScan
@@ -181,7 +98,10 @@ namespace Umbraco.Core.Composing
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
///
- private static readonly string[] KnownAssemblyExclusionFilter = {
+ internal static readonly string[] KnownAssemblyExclusionFilter = {
+ "mscorlib,",
+ "netstandard,",
+ "System,",
"Antlr3.",
"AutoMapper,",
"AutoMapper.",
@@ -228,7 +148,14 @@ namespace Umbraco.Core.Composing
"WebDriver,",
"itextsharp,",
"mscorlib,",
- "nunit.framework,",
+ "NUnit,",
+ "NUnit.",
+ "NUnit3.",
+ "Selenium.",
+ "ImageProcessor",
+ "MiniProfiler.",
+ "Owin,",
+ "SQLite",
};
///
@@ -283,6 +210,9 @@ namespace Umbraco.Core.Composing
return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
}
+ ///
+ public string GetRuntimeHash() => _runtimeHash.GetHashValue();
+
///
/// Returns a Type for the string type name
///
@@ -290,6 +220,11 @@ namespace Umbraco.Core.Composing
///
public virtual Type GetTypeByName(string name)
{
+
+ //NOTE: This will not find types in dynamic assemblies unless those assemblies are already loaded
+ //into the appdomain.
+
+
// This is exactly what the BuildManager does, if the type is an assembly qualified type
// name it will find it.
if (TypeNameContainsAssembly(name))
@@ -340,18 +275,24 @@ namespace Umbraco.Core.Composing
var stack = new Stack();
stack.Push(attributeType.Assembly);
+ if (!QueryWithReferencingAssemblies)
+ {
+ foreach (var a in candidateAssemblies)
+ stack.Push(a);
+ }
+
while (stack.Count > 0)
{
var assembly = stack.Pop();
- Type[] assemblyTypes = null;
+ IReadOnlyList assemblyTypes = null;
if (assembly != attributeType.Assembly || attributeAssemblyIsCandidate)
{
// get all assembly types that can be assigned to baseType
try
{
assemblyTypes = GetTypesWithFormattedException(assembly)
- .ToArray(); // in try block
+ .ToList(); // in try block
}
catch (TypeLoadException ex)
{
@@ -371,10 +312,13 @@ namespace Umbraco.Core.Composing
if (assembly != attributeType.Assembly && assemblyTypes.Where(attributeType.IsAssignableFrom).Any() == false)
continue;
- foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ if (QueryWithReferencingAssemblies)
{
- candidateAssemblies.Remove(referencing);
- stack.Push(referencing);
+ foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ {
+ candidateAssemblies.Remove(referencing);
+ stack.Push(referencing);
+ }
}
}
@@ -405,19 +349,25 @@ namespace Umbraco.Core.Composing
var stack = new Stack();
stack.Push(baseType.Assembly);
+ if (!QueryWithReferencingAssemblies)
+ {
+ foreach (var a in candidateAssemblies)
+ stack.Push(a);
+ }
+
while (stack.Count > 0)
{
var assembly = stack.Pop();
// get all assembly types that can be assigned to baseType
- Type[] assemblyTypes = null;
+ IReadOnlyList assemblyTypes = null;
if (assembly != baseType.Assembly || baseTypeAssemblyIsCandidate)
{
try
{
assemblyTypes = GetTypesWithFormattedException(assembly)
.Where(baseType.IsAssignableFrom)
- .ToArray(); // in try block
+ .ToList(); // in try block
}
catch (TypeLoadException ex)
{
@@ -437,10 +387,13 @@ namespace Umbraco.Core.Composing
if (assembly != baseType.Assembly && assemblyTypes.All(x => x.IsSealed))
continue;
- foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ if (QueryWithReferencingAssemblies)
{
- candidateAssemblies.Remove(referencing);
- stack.Push(referencing);
+ foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
+ {
+ candidateAssemblies.Remove(referencing);
+ stack.Push(referencing);
+ }
}
}
@@ -522,6 +475,5 @@ namespace Umbraco.Core.Composing
#endregion
-
}
}
diff --git a/src/Umbraco.Core/Composing/TypeFinderConfig.cs b/src/Umbraco.Core/Composing/TypeFinderConfig.cs
new file mode 100644
index 0000000000..3dc672b27c
--- /dev/null
+++ b/src/Umbraco.Core/Composing/TypeFinderConfig.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// TypeFinder config via appSettings
+ ///
+ internal class TypeFinderConfig : ITypeFinderConfig
+ {
+ private readonly ITypeFinderSettings _settings;
+ private IEnumerable _assembliesAcceptingLoadExceptions;
+
+ public TypeFinderConfig(ITypeFinderSettings settings)
+ {
+ _settings = settings;
+ }
+
+ public IEnumerable AssembliesAcceptingLoadExceptions
+ {
+ get
+ {
+ if (_assembliesAcceptingLoadExceptions != null)
+ return _assembliesAcceptingLoadExceptions;
+
+ var s = _settings.AssembliesAcceptingLoadExceptions;
+ return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
+ ? Array.Empty()
+ : s.Split(',').Select(x => x.Trim()).ToArray();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Composing/TypeHelper.cs b/src/Umbraco.Core/Composing/TypeHelper.cs
index 28eab6a5ec..1987a4059c 100644
--- a/src/Umbraco.Core/Composing/TypeHelper.cs
+++ b/src/Umbraco.Core/Composing/TypeHelper.cs
@@ -82,9 +82,9 @@ namespace Umbraco.Core.Composing
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
/// reference that assembly, same with the global.asax assembly.
///
- public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies)
+ public static IReadOnlyList GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies)
{
- if (assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
+ if (assembly.IsDynamic || assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
return EmptyAssemblies;
@@ -92,7 +92,7 @@ namespace Umbraco.Core.Composing
// should only be scanning those assemblies because any other assembly will definitely not
// contain sub type's of the one we're currently looking for
var name = assembly.GetName().Name;
- return assemblies.Where(x => x == assembly || HasReference(x, name)).ToArray();
+ return assemblies.Where(x => x == assembly || HasReference(x, name)).ToList();
}
///
diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs
index 76d00c472d..1d40149936 100644
--- a/src/Umbraco.Core/Composing/TypeLoader.cs
+++ b/src/Umbraco.Core/Composing/TypeLoader.cs
@@ -14,8 +14,6 @@ using File = System.IO.File;
namespace Umbraco.Core.Composing
{
-
-
///
/// Provides methods to find and instantiate types.
///
@@ -29,7 +27,6 @@ namespace Umbraco.Core.Composing
{
private const string CacheKey = "umbraco-types.list";
- private readonly IIOHelper _ioHelper;
private readonly IAppPolicyCache _runtimeCache;
private readonly IProfilingLogger _logger;
@@ -49,30 +46,27 @@ namespace Umbraco.Core.Composing
///
/// Initializes a new instance of the class.
///
- ///
///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
///
- public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable assembliesToScan = null)
- : this(ioHelper, typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan)
+ public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable assembliesToScan = null)
+ : this(typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan)
{ }
///
/// Initializes a new instance of the class.
///
- ///
///
/// The application runtime cache.
/// Files storage location.
/// A profiling logger.
/// Whether to detect changes using hashes.
///
- public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable assembliesToScan = null)
+ public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable assembliesToScan = null)
{
TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
- _ioHelper = ioHelper;
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_localTempPath = localTempPath;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -124,7 +118,7 @@ namespace Umbraco.Core.Composing
/// This is for unit tests.
///
// internal for tests
- public IEnumerable AssembliesToScan => _assemblies ?? (_assemblies = TypeFinder.AssembliesToScan);
+ public IEnumerable AssembliesToScan => _assemblies ??= TypeFinder.AssembliesToScan;
///
/// Gets the type lists.
@@ -183,19 +177,7 @@ namespace Umbraco.Core.Composing
if (_currentAssembliesHash != null)
return _currentAssembliesHash;
- _currentAssembliesHash = GetFileHash(new List>
- {
- // TODO: Would be nicer to abstract this logic out into IAssemblyHash
-
- // TODO: Use constants from SystemDirectories when we can (once it's ported to netstandard lib)
-
- // the bin folder and everything in it
- new Tuple(new DirectoryInfo(_ioHelper.MapPath("~/bin")), false),
- // the app code folder and everything in it
- new Tuple(new DirectoryInfo(_ioHelper.MapPath("~/App_Code")), false),
- // global.asax (the app domain also monitors this, if it changes will do a full restart)
- new Tuple(new FileInfo(_ioHelper.MapPath("~/global.asax")), false)
- }, _logger);
+ _currentAssembliesHash = TypeFinder.GetRuntimeHash();
return _currentAssembliesHash;
}
@@ -210,92 +192,6 @@ namespace Umbraco.Core.Composing
File.WriteAllText(typesHashFilePath, CurrentAssembliesHash, Encoding.UTF8);
}
- ///
- /// Returns a unique hash for a combination of FileInfo objects.
- ///
- /// A collection of files.
- /// A profiling logger.
- /// The hash.
- /// Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the
- /// file properties (false) or the file contents (true).
- private static string GetFileHash(IEnumerable> filesAndFolders, IProfilingLogger logger)
- {
- using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
- {
- // get the distinct file infos to hash
- var uniqInfos = new HashSet();
- var uniqContent = new HashSet();
- using (var generator = new HashGenerator())
- {
- foreach (var fileOrFolder in filesAndFolders)
- {
- var info = fileOrFolder.Item1;
- if (fileOrFolder.Item2)
- {
- // add each unique file's contents to the hash
- // normalize the content for cr/lf and case-sensitivity
- if (uniqContent.Add(info.FullName))
- {
- if (File.Exists(info.FullName) == false) continue;
- var content = RemoveCrLf(File.ReadAllText(info.FullName));
- generator.AddCaseInsensitiveString(content);
- }
- }
- else
- {
- // add each unique folder/file to the hash
- if (uniqInfos.Add(info.FullName))
- {
- generator.AddFileSystemItem(info);
- }
- }
- }
- return generator.GenerateHash();
- }
- }
- }
-
- // fast! (yes, according to benchmarks)
- private static string RemoveCrLf(string s)
- {
- var buffer = new char[s.Length];
- var count = 0;
- // ReSharper disable once ForCanBeConvertedToForeach - no!
- for (var i = 0; i < s.Length; i++)
- {
- if (s[i] != '\r' && s[i] != '\n')
- buffer[count++] = s[i];
- }
- return new string(buffer, 0, count);
- }
-
- ///
- /// Returns a unique hash for a combination of FileInfo objects.
- ///
- /// A collection of files.
- /// A profiling logger.
- /// The hash.
- // internal for tests
- public static string GetFileHash(IEnumerable filesAndFolders, IProfilingLogger logger)
- {
- using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined"))
- {
- using (var generator = new HashGenerator())
- {
- // get the distinct file infos to hash
- var uniqInfos = new HashSet();
-
- foreach (var fileOrFolder in filesAndFolders)
- {
- if (uniqInfos.Contains(fileOrFolder.FullName)) continue;
- uniqInfos.Add(fileOrFolder.FullName);
- generator.AddFileSystemItem(fileOrFolder);
- }
- return generator.GenerateHash();
- }
- }
- }
-
#endregion
#region Cache
@@ -516,29 +412,29 @@ namespace Umbraco.Core.Composing
#region Get Assembly Attributes
- ///
- /// Gets the assembly attributes of the specified type .
- ///
- /// The attribute type.
- ///
- /// The assembly attributes of the specified type .
- ///
- public IEnumerable GetAssemblyAttributes()
- where T : Attribute
- {
- return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
- }
+ /////
+ ///// Gets the assembly attributes of the specified type .
+ /////
+ ///// The attribute type.
+ /////
+ ///// The assembly attributes of the specified type .
+ /////
+ //public IEnumerable GetAssemblyAttributes()
+ // where T : Attribute
+ //{
+ // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
+ //}
- ///
- /// Gets all the assembly attributes.
- ///
- ///
- /// All assembly attributes.
- ///
- public IEnumerable GetAssemblyAttributes()
- {
- return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
- }
+ /////
+ ///// Gets all the assembly attributes.
+ /////
+ /////
+ ///// All assembly attributes.
+ /////
+ //public IEnumerable GetAssemblyAttributes()
+ //{
+ // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
+ //}
///
/// Gets the assembly attributes of the specified .
diff --git a/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs b/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs
new file mode 100644
index 0000000000..034af3b80c
--- /dev/null
+++ b/src/Umbraco.Core/Composing/VaryingRuntimeHash.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Umbraco.Core.Composing
+{
+ ///
+ /// A runtime hash this is always different on each app startup
+ ///
+ public sealed class VaryingRuntimeHash : IRuntimeHash
+ {
+ private readonly string _hash;
+
+ public VaryingRuntimeHash()
+ {
+ _hash = DateTime.Now.Ticks.ToString();
+ }
+
+ public string GetHashValue() => _hash;
+ }
+}
diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs
index bea78f82ed..bbea868f55 100644
--- a/src/Umbraco.Core/CompositionExtensions.cs
+++ b/src/Umbraco.Core/CompositionExtensions.cs
@@ -1,6 +1,13 @@
using Umbraco.Core.Composing;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Web.Actions;
+using Umbraco.Web.ContentApps;
using Umbraco.Web.Dashboards;
+using Umbraco.Web.Editors;
+using Umbraco.Web.HealthCheck;
+using Umbraco.Web.Routing;
+using Umbraco.Web.Sections;
+using Umbraco.Web.Tour;
namespace Umbraco.Core
{
@@ -9,6 +16,72 @@ namespace Umbraco.Core
#region Collection Builders
+ ///
+ /// Gets the actions collection builder.
+ ///
+ /// The composition.
+ ///
+ public static ActionCollectionBuilder Actions(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the content apps collection builder.
+ ///
+ /// The composition.
+ ///
+ public static ContentAppFactoryCollectionBuilder ContentApps(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the content finders collection builder.
+ ///
+ /// The composition.
+ ///
+ public static ContentFinderCollectionBuilder ContentFinders(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the editor validators collection builder.
+ ///
+ /// The composition.
+ ///
+ public static EditorValidatorCollectionBuilder EditorValidators(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the health checks collection builder.
+ ///
+ /// The composition.
+ public static HealthCheckCollectionBuilder HealthChecks(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the TourFilters collection builder.
+ ///
+ public static TourFilterCollectionBuilder TourFilters(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the url providers collection builder.
+ ///
+ /// The composition.
+ public static UrlProviderCollectionBuilder UrlProviders(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the media url providers collection builder.
+ ///
+ /// The composition.
+ public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this Composition composition)
+ => composition.WithCollectionBuilder();
+
+ ///
+ /// Gets the backoffice sections/applications collection builder.
+ ///
+ /// The composition.
+ public static SectionCollectionBuilder Sections(this Composition composition)
+ => composition.WithCollectionBuilder();
+
///
/// Gets the components collection builder.
///
diff --git a/src/Umbraco.Core/CompositionExtensions_Uniques.cs b/src/Umbraco.Core/CompositionExtensions_Uniques.cs
index 52f1ce7ecd..8352eb33ec 100644
--- a/src/Umbraco.Core/CompositionExtensions_Uniques.cs
+++ b/src/Umbraco.Core/CompositionExtensions_Uniques.cs
@@ -31,5 +31,20 @@ namespace Umbraco.Core
///
public static void RegisterUnique(this Composition composition, TService instance)
=> composition.RegisterUnique(typeof(TService), instance);
+
+
+
+ ///
+ /// Registers a unique service with an implementation type.
+ ///
+ public static void RegisterMultipleUnique(this Composition composition)
+ where TImplementing : class, TService1, TService2
+ where TService1 : class
+ where TService2 : class
+ {
+ composition.RegisterUnique();
+ composition.RegisterUnique(factory => factory.GetInstance());
+ composition.RegisterUnique(factory => factory.GetInstance());
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Core/Configuration/Configs.cs b/src/Umbraco.Core/Configuration/Configs.cs
index abb06d525f..821ee308f0 100644
--- a/src/Umbraco.Core/Configuration/Configs.cs
+++ b/src/Umbraco.Core/Configuration/Configs.cs
@@ -13,16 +13,8 @@ namespace Umbraco.Core.Configuration
///
public class Configs
{
- private readonly Func _configSectionResolver;
-
- public Configs(Func configSectionResolver)
- {
- _configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver));
- }
-
private readonly Dictionary> _configs = new Dictionary>();
private Dictionary> _registerings = new Dictionary>();
- private Lazy _factory;
///
/// Gets a configuration.
@@ -52,61 +44,15 @@ namespace Umbraco.Core.Configuration
_registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton);
}
- ///
- /// Adds a configuration, provided by a factory.
- ///
- public void Add(Func configFactory)
- where TConfig : class
- {
- // make sure it is not too late
- if (_registerings == null)
- throw new InvalidOperationException("Configurations have already been registered.");
-
- var typeOfConfig = typeof(TConfig);
-
- _configs[typeOfConfig] = new Lazy
public static class ConfigsExtensions
{
+
+ public static IImagingSettings Imaging(this Configs configs)
+ => configs.GetConfig();
public static IGlobalSettings Global(this Configs configs)
=> configs.GetConfig();
@@ -25,47 +22,28 @@ namespace Umbraco.Core
public static IConnectionStrings ConnectionStrings(this Configs configs)
=> configs.GetConfig();
- public static IUmbracoSettingsSection Settings(this Configs configs)
- => configs.GetConfig();
+ public static IContentSettings Content(this Configs configs)
+ => configs.GetConfig();
- public static IHealthChecks HealthChecks(this Configs configs)
- => configs.GetConfig();
+ public static ISecuritySettings Security(this Configs configs)
+ => configs.GetConfig();
- public static IGridConfig Grids(this Configs configs)
- => configs.GetConfig();
-
- public static ICoreDebug CoreDebug(this Configs configs)
- => configs.GetConfig();
public static IUserPasswordConfiguration UserPasswordConfiguration(this Configs configs)
=> configs.GetConfig();
-
public static IMemberPasswordConfiguration MemberPasswordConfiguration(this Configs configs)
=> configs.GetConfig();
- public static void AddPasswordConfigurations(this Configs configs)
- {
- configs.Add(() =>
- {
- return new UserPasswordConfiguration(configs.Settings().Security.UserPasswordConfiguration);
- });
- configs.Add(() =>
- {
- return new MemberPasswordConfiguration(configs.Settings().Security.MemberPasswordConfiguration);
- });
- }
+ public static IRequestHandlerSettings RequestHandler(this Configs configs)
+ => configs.GetConfig();
- public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper)
- {
- var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config));
+ public static IWebRoutingSettings WebRouting(this Configs configs)
+ => configs.GetConfig();
+
+ public static IHealthChecksSettings HealthChecks(this Configs configs)
+ => configs.GetConfig();
+ public static ICoreDebugSettings CoreDebug(this Configs configs)
+ => configs.GetConfig();
- // GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition
- configs.Add(factory => new GridConfig(
- factory.GetInstance(),
- factory.GetInstance(),
- configDir,
- factory.GetInstance(),
- factory.GetInstance().Debug));
- }
}
}
diff --git a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs
index 4d8039dfbb..a9a7f578d0 100644
--- a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs
+++ b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs
@@ -1,12 +1,25 @@
using System;
-using Umbraco.Core.IO;
+using Umbraco.Core.Hosting;
namespace Umbraco.Core.Configuration
{
public static class GlobalSettingsExtensions
{
private static string _mvcArea;
+ private static string _backOfficePath;
+ ///
+ /// Returns the absolute path for the Umbraco back office
+ ///
+ ///
+ ///
+ ///
+ public static string GetBackOfficePath(this IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
+ {
+ if (_backOfficePath != null) return _backOfficePath;
+ _backOfficePath = hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath);
+ return _backOfficePath;
+ }
///
/// This returns the string of the MVC Area route.
@@ -19,27 +32,27 @@ namespace Umbraco.Core.Configuration
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
///
- public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IIOHelper ioHelper)
+ public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
{
if (_mvcArea != null) return _mvcArea;
- _mvcArea = GetUmbracoMvcAreaNoCache(globalSettings, ioHelper);
+ _mvcArea = globalSettings.GetUmbracoMvcAreaNoCache(hostingEnvironment);
return _mvcArea;
}
- internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IIOHelper ioHelper)
+ internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
{
- if (globalSettings.Path.IsNullOrWhiteSpace())
- {
- throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
- }
+ var path = string.IsNullOrEmpty(globalSettings.UmbracoPath)
+ ? string.Empty
+ : hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath);
- var path = globalSettings.Path;
- if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518
- path = path.Substring(ioHelper.Root.Length);
+ if (path.IsNullOrWhiteSpace())
+ throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
+
+ if (path.StartsWith(hostingEnvironment.ApplicationVirtualPath)) // beware of TrimStart, see U4-2518
+ path = path.Substring(hostingEnvironment.ApplicationVirtualPath.Length);
return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
}
-
}
}
diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
index de4f7ccd5a..72c720e3d6 100644
--- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
+++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs
@@ -1,15 +1,18 @@
using System.IO;
using Umbraco.Core.Cache;
+using Umbraco.Core.Hosting;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
+using Umbraco.Core.Serialization;
namespace Umbraco.Core.Configuration.Grid
{
public class GridConfig : IGridConfig
{
- public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
+ public GridConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment)
{
- EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug);
+ EditorsConfig = new GridEditorsConfig(appCaches, ioHelper, manifestParser, jsonSerializer, hostingEnvironment.IsDebugMode);
}
public IGridEditorsConfig EditorsConfig { get; }
diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
index a1ebf008fc..410c83ff1a 100644
--- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
+++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs
@@ -1,27 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
+using Umbraco.Composing;
using Umbraco.Core.Cache;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.Serialization;
namespace Umbraco.Core.Configuration.Grid
{
internal class GridEditorsConfig : IGridEditorsConfig
{
- private readonly ILogger _logger;
private readonly AppCaches _appCaches;
- private readonly DirectoryInfo _configFolder;
+ private readonly IIOHelper _ioHelper;
private readonly IManifestParser _manifestParser;
private readonly bool _isDebug;
+ private readonly IJsonSerializer _jsonSerializer;
- public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
+ public GridEditorsConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser,IJsonSerializer jsonSerializer, bool isDebug)
{
- _logger = logger;
_appCaches = appCaches;
- _configFolder = configFolder;
+ _ioHelper = ioHelper;
_manifestParser = manifestParser;
+ _jsonSerializer = jsonSerializer;
_isDebug = isDebug;
}
@@ -31,19 +34,20 @@ namespace Umbraco.Core.Configuration.Grid
{
List GetResult()
{
+ var configFolder = new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.Config));
var editors = new List();
- var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
+ var gridConfig = Path.Combine(configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
var sourceString = File.ReadAllText(gridConfig);
try
{
- editors.AddRange(_manifestParser.ParseGridEditors(sourceString));
+ editors.AddRange(_jsonSerializer.Deserialize>(sourceString));
}
catch (Exception ex)
{
- _logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
+ Current.Logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
}
}
@@ -63,7 +67,6 @@ namespace Umbraco.Core.Configuration.Grid
return result;
}
-
}
}
}
diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
similarity index 84%
rename from src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs
rename to src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
index fa98e3b054..785e8d5651 100644
--- a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs
+++ b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
- public interface IHealthChecks
+ public interface IHealthChecksSettings
{
IEnumerable DisabledChecks { get; }
IHealthCheckNotificationSettings NotificationSettings { get; }
diff --git a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs
index 58172ba063..e6ec49a1e7 100644
--- a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs
+++ b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs
@@ -13,13 +13,13 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Configuration")]
public class TrySkipIisCustomErrorsCheck : AbstractConfigCheck
{
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly Version _iisVersion;
public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService, IIOHelper ioHelper, ILogger logger,
IHostingEnvironment hostingEnvironment)
: base(textService, ioHelper, logger)
{
- _hostingEnvironment = hostingEnvironment;
+ _iisVersion = hostingEnvironment.IISVersion;
}
public override string FilePath => "~/Config/umbracoSettings.config";
@@ -33,7 +33,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get
{
// beware! 7.5 and 7.5.0 are not the same thing!
- var recommendedValue = _hostingEnvironment.IISVersion >= new Version("7.5")
+ var recommendedValue = _iisVersion >= new Version("7.5")
? bool.TrueString.ToLower()
: bool.FalseString.ToLower();
return new List { new AcceptableConfiguration { IsRecommended = true, Value = recommendedValue } };
@@ -45,7 +45,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckSuccessMessage",
- new[] { Values.First(v => v.IsRecommended).Value, _hostingEnvironment.IISVersion.ToString() });
+ new[] { Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() });
}
}
@@ -54,7 +54,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckErrorMessage",
- new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, _hostingEnvironment.IISVersion.ToString() });
+ new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() });
}
}
@@ -63,7 +63,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckRectifySuccessMessage",
- new[] { Values.First(v => v.IsRecommended).Value, _hostingEnvironment.IISVersion.ToString() });
+ new[] { Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() });
}
}
}
diff --git a/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs b/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs
new file mode 100644
index 0000000000..e6b9202c06
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IActiveDirectorySettings
+ {
+ string ActiveDirectoryDomain { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IConfigManipulator.cs b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
new file mode 100644
index 0000000000..1d9230be44
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
@@ -0,0 +1,11 @@
+using Umbraco.Core.IO;
+
+namespace Umbraco.Core.Configuration
+{
+ public interface IConfigManipulator
+ {
+ void RemoveConnectionString();
+ void SaveConnectionString(string connectionString, string providerName);
+ void SaveConfigValue(string itemPath, object value);
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IConfigsFactory.cs b/src/Umbraco.Core/Configuration/IConfigsFactory.cs
index 98a24ca37f..dd2459b88c 100644
--- a/src/Umbraco.Core/Configuration/IConfigsFactory.cs
+++ b/src/Umbraco.Core/Configuration/IConfigsFactory.cs
@@ -1,9 +1,10 @@
using Umbraco.Core.IO;
+using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
public interface IConfigsFactory
{
- Configs Create(IIOHelper ioHelper);
+ Configs Create();
}
}
diff --git a/src/Umbraco.Core/Configuration/IConnectionStrings.cs b/src/Umbraco.Core/Configuration/IConnectionStrings.cs
index acd2281a1e..0d33378669 100644
--- a/src/Umbraco.Core/Configuration/IConnectionStrings.cs
+++ b/src/Umbraco.Core/Configuration/IConnectionStrings.cs
@@ -6,7 +6,5 @@ namespace Umbraco.Core.Configuration
{
get;
}
-
- void RemoveConnectionString(string umbracoConnectionName);
}
}
diff --git a/src/Umbraco.Core/Configuration/ICoreDebug.cs b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
similarity index 93%
rename from src/Umbraco.Core/Configuration/ICoreDebug.cs
rename to src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
index 4ff2a1a300..586e4bc3e4 100644
--- a/src/Umbraco.Core/Configuration/ICoreDebug.cs
+++ b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration
{
- public interface ICoreDebug
+ public interface ICoreDebugSettings
{
///
/// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed.
diff --git a/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs b/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs
new file mode 100644
index 0000000000..169c04da5f
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IExceptionFilterSettings
+ {
+ bool Disabled { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
index 1b1f328142..434aef6e68 100644
--- a/src/Umbraco.Core/Configuration/IGlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/IGlobalSettings.cs
@@ -20,11 +20,6 @@
/// The reserved paths.
string ReservedPaths { get; }
- ///
- /// Gets the path to umbraco's root directory (/umbraco by default).
- ///
- string Path { get; }
-
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
///
@@ -61,6 +56,9 @@
/// The version check period in days (0 = never).
int VersionCheckPeriod { get; }
+ ///
+ /// Gets the path to umbraco's root directory.
+ ///
string UmbracoPath { get; }
string UmbracoCssPath { get; }
string UmbracoScriptsPath { get; }
@@ -95,5 +93,11 @@
bool DisableElectionForSingleServer { get; }
string RegisterType { get; }
string DatabaseFactoryServerVersion { get; }
+ string MainDomLock { get; }
+
+ ///
+ /// Gets the path to the razor file used when no published content is available.
+ ///
+ string NoNodesViewPath { get; }
}
}
diff --git a/src/Umbraco.Core/Configuration/IHostingSettings.cs b/src/Umbraco.Core/Configuration/IHostingSettings.cs
index ef399177a4..48ff4f216e 100644
--- a/src/Umbraco.Core/Configuration/IHostingSettings.cs
+++ b/src/Umbraco.Core/Configuration/IHostingSettings.cs
@@ -1,11 +1,24 @@
+using Umbraco.Core.Hosting;
+
namespace Umbraco.Core.Configuration
{
public interface IHostingSettings
{
bool DebugMode { get; }
+
///
/// Gets the configuration for the location of temporary files.
///
LocalTempStorage LocalTempStorageLocation { get; }
+
+ ///
+ /// Optional property to explicitly configure the application's virtual path
+ ///
+ ///
+ /// By default this is null which will mean that the is automatically configured,
+ /// otherwise this explicitly sets it.
+ /// If set, this value must begin with a "/" and cannot end with "/".
+ ///
+ string ApplicationVirtualPath { get; }
}
}
diff --git a/src/Umbraco.Core/Configuration/IImagingSettings.cs b/src/Umbraco.Core/Configuration/IImagingSettings.cs
new file mode 100644
index 0000000000..13e1b30389
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IImagingSettings.cs
@@ -0,0 +1,12 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IImagingSettings
+ {
+ int MaxBrowserCacheDays { get;}
+ int MaxCacheDays { get; }
+ uint CachedNameLength { get; }
+ int MaxResizeWidth { get; }
+ int MaxResizeHeight { get; }
+ string CacheFolder { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IIndexCreatorSettings.cs b/src/Umbraco.Core/Configuration/IIndexCreatorSettings.cs
new file mode 100644
index 0000000000..b3e2854a0d
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IIndexCreatorSettings.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IIndexCreatorSettings
+ {
+ string LuceneDirectoryFactory { get; }
+ }
+}
diff --git a/src/Umbraco.ModelsBuilder.Embedded/Configuration/IModelsBuilderConfig.cs b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
similarity index 80%
rename from src/Umbraco.ModelsBuilder.Embedded/Configuration/IModelsBuilderConfig.cs
rename to src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
index 7e96aec60e..990bde9843 100644
--- a/src/Umbraco.ModelsBuilder.Embedded/Configuration/IModelsBuilderConfig.cs
+++ b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs
@@ -1,4 +1,4 @@
-namespace Umbraco.ModelsBuilder.Embedded.Configuration
+namespace Umbraco.Core.Configuration
{
public interface IModelsBuilderConfig
{
@@ -7,7 +7,6 @@
int DebugLevel { get; }
bool EnableFactory { get; }
bool FlagOutOfDateModels { get; }
- bool IsDebug { get; }
string ModelsDirectory { get; }
ModelsMode ModelsMode { get; }
string ModelsNamespace { get; }
diff --git a/src/Umbraco.Core/Configuration/INuCacheSettings.cs b/src/Umbraco.Core/Configuration/INuCacheSettings.cs
new file mode 100644
index 0000000000..c6524297a6
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/INuCacheSettings.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface INuCacheSettings
+ {
+ string BTreeBlockSize { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
index 98cd1010c0..6a5fd8e73f 100644
--- a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs
@@ -6,13 +6,11 @@
///
public interface IPasswordConfiguration
{
- int RequiredLength { get; }
+ int RequiredLength { get; }
bool RequireNonLetterOrDigit { get; }
bool RequireDigit { get; }
bool RequireLowercase { get; }
bool RequireUppercase { get; }
-
- bool UseLegacyEncoding { get; }
string HashAlgorithmType { get; }
// TODO: This doesn't really belong here
diff --git a/src/Umbraco.Core/Configuration/IRuntimeSettings.cs b/src/Umbraco.Core/Configuration/IRuntimeSettings.cs
new file mode 100644
index 0000000000..915e774186
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/IRuntimeSettings.cs
@@ -0,0 +1,8 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface IRuntimeSettings
+ {
+ int? MaxQueryStringLength { get; }
+ int? MaxRequestLength { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/ITypeFinderSettings.cs b/src/Umbraco.Core/Configuration/ITypeFinderSettings.cs
new file mode 100644
index 0000000000..15e72a1f40
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/ITypeFinderSettings.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Configuration
+{
+ public interface ITypeFinderSettings
+ {
+ string AssembliesAcceptingLoadExceptions { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs
index 58c907c31f..8e7cd97f35 100644
--- a/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration
///
public class MemberPasswordConfiguration : PasswordConfiguration, IMemberPasswordConfiguration
{
- public MemberPasswordConfiguration(IMemberPasswordConfigurationSection configSection)
- : base(configSection)
- {
+ public MemberPasswordConfiguration(IMemberPasswordConfiguration configSettings)
+ : base(configSettings)
+ {
}
}
}
diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs
new file mode 100644
index 0000000000..3e3b116395
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs
@@ -0,0 +1,57 @@
+using System.Configuration;
+using System.IO;
+using Umbraco.Core.IO;
+
+namespace Umbraco.Core.Configuration
+{
+ public static class ModelsBuilderConfigExtensions
+ {
+ private static string _modelsDirectoryAbsolute = null;
+
+ public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IIOHelper ioHelper)
+ {
+
+ if (_modelsDirectoryAbsolute is null)
+ {
+ var modelsDirectory = modelsBuilderConfig.ModelsDirectory;
+ var root = ioHelper.MapPath("~/");
+
+ _modelsDirectoryAbsolute = GetModelsDirectory(root, modelsDirectory,
+ modelsBuilderConfig.AcceptUnsafeModelsDirectory);
+ }
+
+ return _modelsDirectoryAbsolute;
+ }
+
+ // internal for tests
+ internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe)
+ {
+ // making sure it is safe, ie under the website root,
+ // unless AcceptUnsafeModelsDirectory and then everything is OK.
+
+ if (!Path.IsPathRooted(root))
+ throw new ConfigurationErrorsException($"Root is not rooted \"{root}\".");
+
+ if (config.StartsWith("~/"))
+ {
+ var dir = Path.Combine(root, config.TrimStart("~/"));
+
+ // sanitize - GetFullPath will take care of any relative
+ // segments in path, eg '../../foo.tmp' - it may throw a SecurityException
+ // if the combined path reaches illegal parts of the filesystem
+ dir = Path.GetFullPath(dir);
+ root = Path.GetFullPath(root);
+
+ if (!dir.StartsWith(root) && !acceptUnsafe)
+ throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
+
+ return dir;
+ }
+
+ if (acceptUnsafe)
+ return Path.GetFullPath(config);
+
+ throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
+ }
+ }
+}
diff --git a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsMode.cs b/src/Umbraco.Core/Configuration/ModelsMode.cs
similarity index 92%
rename from src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsMode.cs
rename to src/Umbraco.Core/Configuration/ModelsMode.cs
index e0286fdab1..2483367394 100644
--- a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsMode.cs
+++ b/src/Umbraco.Core/Configuration/ModelsMode.cs
@@ -1,4 +1,4 @@
-namespace Umbraco.ModelsBuilder.Embedded.Configuration
+namespace Umbraco.Core.Configuration
{
///
/// Defines the models generation modes.
@@ -8,7 +8,7 @@
///
/// Do not generate models.
///
- Nothing = 0, // default value
+ Nothing = 0, // default value
///
/// Generate models in memory.
diff --git a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsModeExtensions.cs b/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs
similarity index 94%
rename from src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsModeExtensions.cs
rename to src/Umbraco.Core/Configuration/ModelsModeExtensions.cs
index be638729ea..8d1b51cd28 100644
--- a/src/Umbraco.ModelsBuilder.Embedded/Configuration/ModelsModeExtensions.cs
+++ b/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs
@@ -1,4 +1,6 @@
-namespace Umbraco.ModelsBuilder.Embedded.Configuration
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Configuration
{
///
/// Provides extensions for the enumeration.
diff --git a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
index 9edf1a462e..0c5ed9adb0 100644
--- a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs
@@ -5,21 +5,20 @@ namespace Umbraco.Core.Configuration
{
public abstract class PasswordConfiguration : IPasswordConfiguration
{
- protected PasswordConfiguration(IPasswordConfigurationSection configSection)
+ protected PasswordConfiguration(IPasswordConfiguration configSettings)
{
- if (configSection == null)
+ if (configSettings == null)
{
- throw new ArgumentNullException(nameof(configSection));
+ throw new ArgumentNullException(nameof(configSettings));
}
- RequiredLength = configSection.RequiredLength;
- RequireNonLetterOrDigit = configSection.RequireNonLetterOrDigit;
- RequireDigit = configSection.RequireDigit;
- RequireLowercase = configSection.RequireLowercase;
- RequireUppercase = configSection.RequireUppercase;
- UseLegacyEncoding = configSection.UseLegacyEncoding;
- HashAlgorithmType = configSection.HashAlgorithmType;
- MaxFailedAccessAttemptsBeforeLockout = configSection.MaxFailedAccessAttemptsBeforeLockout;
+ RequiredLength = configSettings.RequiredLength;
+ RequireNonLetterOrDigit = configSettings.RequireNonLetterOrDigit;
+ RequireDigit = configSettings.RequireDigit;
+ RequireLowercase = configSettings.RequireLowercase;
+ RequireUppercase = configSettings.RequireUppercase;
+ HashAlgorithmType = configSettings.HashAlgorithmType;
+ MaxFailedAccessAttemptsBeforeLockout = configSettings.MaxFailedAccessAttemptsBeforeLockout;
}
public int RequiredLength { get; }
@@ -32,8 +31,6 @@ namespace Umbraco.Core.Configuration
public bool RequireUppercase { get; }
- public bool UseLegacyEncoding { get; }
-
public string HashAlgorithmType { get; }
public int MaxFailedAccessAttemptsBeforeLockout { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs
index 82cc5928cf..d100eb0a74 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
/// The file extension.
///
/// A value indicating whether the file extension corresponds to an image.
- public static bool IsImageFile(this IContentSection contentConfig, string extension)
+ public static bool IsImageFile(this IContentSettings contentConfig, string extension)
{
if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig));
if (extension == null) return false;
@@ -24,22 +24,22 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
/// held in settings.
/// Allow upload if extension is whitelisted OR if there is no whitelist and extension is NOT blacklisted.
///
- public static bool IsFileAllowedForUpload(this IContentSection contentSection, string extension)
+ public static bool IsFileAllowedForUpload(this IContentSettings contentSettings, string extension)
{
- return contentSection.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) ||
- (contentSection.AllowedUploadFiles.Any() == false &&
- contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
+ return contentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) ||
+ (contentSettings.AllowedUploadFiles.Any() == false &&
+ contentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
}
///
/// Gets the auto-fill configuration for a specified property alias.
///
- ///
+ ///
/// The property type alias.
/// The auto-fill configuration for the specified property alias, or null.
- public static IImagingAutoFillUploadField GetConfig(this IContentSection contentSection, string propertyTypeAlias)
+ public static IImagingAutoFillUploadField GetConfig(this IContentSettings contentSettings, string propertyTypeAlias)
{
- var autoFillConfigs = contentSection.ImageAutoFillProperties;
+ var autoFillConfigs = contentSettings.ImageAutoFillProperties;
return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias);
}
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs
index 36dd6a22ed..85df4540c0 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs
@@ -2,6 +2,6 @@
{
public interface IBackOfficeSection
{
- ITourSection Tours { get; }
+ ITourSettings Tours { get; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs
similarity index 93%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs
index 228b0923dc..08f6231309 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs
@@ -3,7 +3,7 @@ using Umbraco.Core.Macros;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface IContentSection : IUmbracoConfigurationSection
+ public interface IContentSettings : IUmbracoConfigurationSection
{
string NotificationEmailAddress { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs
similarity index 68%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs
index 3a0ad258c5..58a8151474 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface IKeepAliveSection : IUmbracoConfigurationSection
+ public interface IKeepAliveSettings : IUmbracoConfigurationSection
{
bool DisableKeepAliveTask { get; }
string KeepAlivePingUrl { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs
similarity index 66%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs
index 6c1be8ade5..ee5647ee27 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface ILoggingSection : IUmbracoConfigurationSection
+ public interface ILoggingSettings : IUmbracoConfigurationSection
{
int MaxLogAge { get; }
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs
deleted file mode 100644
index cbbb933857..0000000000
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Umbraco.Core.Configuration.UmbracoSettings
-{
- public interface IMemberPasswordConfigurationSection : IPasswordConfigurationSection
- {
- }
-}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs
similarity index 78%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs
index 2393c5af63..11fdaa8310 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface IRequestHandlerSection : IUmbracoConfigurationSection
+ public interface IRequestHandlerSettings : IUmbracoConfigurationSection
{
bool AddTrailingSlash { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs
similarity index 78%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs
index a6ed188713..6ab520fefd 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs
@@ -1,9 +1,9 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface ISecuritySection : IUmbracoConfigurationSection
+ public interface ISecuritySettings : IUmbracoConfigurationSection
{
bool KeepUserLoggedIn { get; }
-
+
bool HideDisabledUsersInBackoffice { get; }
///
@@ -23,9 +23,5 @@
/// When this is false, the username and email fields will be shown in the user section.
///
bool UsernameIsEmail { get; }
-
- IUserPasswordConfigurationSection UserPasswordConfiguration { get; }
-
- IMemberPasswordConfigurationSection MemberPasswordConfiguration { get; }
}
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs
similarity index 75%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs
index 938642521e..d3d8293140 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface ITourSection
+ public interface ITourSettings
{
bool EnableTours { get; }
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ITypeFinderConfig.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ITypeFinderConfig.cs
index fd5b18ed39..a290c26d15 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ITypeFinderConfig.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ITypeFinderConfig.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Collections.Generic;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs
deleted file mode 100644
index acd9c92588..0000000000
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace Umbraco.Core.Configuration.UmbracoSettings
-{
- public interface IUmbracoSettingsSection : IUmbracoConfigurationSection
- {
- IBackOfficeSection BackOffice { get; }
-
- IContentSection Content { get; }
-
- ISecuritySection Security { get; }
-
- IRequestHandlerSection RequestHandler { get; }
-
- ILoggingSection Logging { get; }
-
- IWebRoutingSection WebRouting { get; }
-
- IKeepAliveSection KeepAlive { get; }
- }
-}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs
deleted file mode 100644
index d80dd2b7e5..0000000000
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Umbraco.Core.Configuration.UmbracoSettings
-{
- public interface IUserPasswordConfigurationSection : IPasswordConfigurationSection
- {
- }
-}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs
similarity index 86%
rename from src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs
rename to src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs
index f0a986efe2..f7f6a94d30 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- public interface IWebRoutingSection : IUmbracoConfigurationSection
+ public interface IWebRoutingSettings : IUmbracoConfigurationSection
{
bool TrySkipIisCustomErrors { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
index dd96e6edd7..35154a9f50 100644
--- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Configuration
private readonly IGlobalSettings _globalSettings;
public UmbracoVersion(IGlobalSettings globalSettings)
- :this()
+ : this()
{
_globalSettings = globalSettings;
}
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Configuration
/// Is the one that the CLR checks for compatibility. Therefore, it changes only on
/// hard-breaking changes (for instance, on new major versions).
///
- public Version AssemblyVersion {get; }
+ public Version AssemblyVersion { get; }
///
/// Gets the assembly file version of the Umbraco code.
@@ -83,11 +83,13 @@ namespace Umbraco.Core.Configuration
/// and changes during an upgrade. The executing code version changes when new code is
/// deployed. The site/files version changes during an upgrade.
///
- public SemVersion LocalVersion {
+ public SemVersion LocalVersion
+ {
get
{
var value = _globalSettings.ConfigurationStatus;
return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
- } }
+ }
+ }
}
}
diff --git a/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs
index 4cfee5280b..07e6603cee 100644
--- a/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration
///
public class UserPasswordConfiguration : PasswordConfiguration, IUserPasswordConfiguration
{
- public UserPasswordConfiguration(IUserPasswordConfigurationSection configSection)
- : base(configSection)
- {
+ public UserPasswordConfiguration(IUserPasswordConfiguration configSettings)
+ : base(configSettings)
+ {
}
}
}
diff --git a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
new file mode 100644
index 0000000000..80d795bb48
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
@@ -0,0 +1,123 @@
+using System;
+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 XmlConfigManipulator : IConfigManipulator
+ {
+ private readonly IIOHelper _ioHelper;
+ private readonly ILogger _logger;
+
+ public XmlConfigManipulator(IIOHelper ioHelper, ILogger logger)
+ {
+ _ioHelper = ioHelper;
+ _logger = logger;
+ }
+
+ public void RemoveConnectionString()
+ {
+ var key = Constants.System.UmbracoConnectionName;
+ var fileName = _ioHelper.MapPath("~/web.config");
+ var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
+
+ var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
+ var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
+
+ if (setting != null)
+ {
+ setting.Remove();
+ xml.Save(fileName, SaveOptions.DisableFormatting);
+ ConfigurationManager.RefreshSection("appSettings");
+ }
+
+ var settings = ConfigurationManager.ConnectionStrings[key];
+ }
+
+ ///
+ /// Saves the connection string as a proper .net connection string in web.config.
+ ///
+ /// Saves the ConnectionString in the very nasty 'medium trust'-supportive way.
+ /// The connection string.
+ /// The provider name.
+ 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 (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));
+
+
+ var fileSource = "web.config";
+ var fileName = _ioHelper.MapPath("~/" + fileSource);
+
+ var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
+ if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
+
+ var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
+ if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings).");
+
+ // handle configSource
+ var configSourceAttribute = connectionStrings.Attribute("configSource");
+ if (configSourceAttribute != null)
+ {
+ fileSource = configSourceAttribute.Value;
+ fileName = _ioHelper.MapPath("~/" + fileSource);
+
+ if (!File.Exists(fileName))
+ throw new Exception($"Invalid configSource \"{fileSource}\" (no such file).");
+
+ xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
+ 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).");
+ }
+
+ // create or update connection string
+ var setting = connectionStrings.Descendants("add").FirstOrDefault(s =>
+ s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName);
+ if (setting == null)
+ {
+ connectionStrings.Add(new XElement("add",
+ new XAttribute("name", Constants.System.UmbracoConnectionName),
+ new XAttribute("connectionString", connectionString),
+ new XAttribute("providerName", providerName)));
+ }
+ else
+ {
+ AddOrUpdateAttribute(setting, "connectionString", connectionString);
+ AddOrUpdateAttribute(setting, "providerName", providerName);
+ }
+
+ // save
+ _logger.Info("Saving connection string to {ConfigFile}.", fileSource);
+ xml.Save(fileName, SaveOptions.DisableFormatting);
+ _logger.Info("Saved connection string to {ConfigFile}.", fileSource);
+ }
+
+ public void SaveConfigValue(string itemPath, object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ private static void AddOrUpdateAttribute(XElement element, string name, string value)
+ {
+ var attribute = element.Attribute(name);
+ if (attribute == null)
+ element.Add(new XAttribute(name, value));
+ else
+ attribute.Value = value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs
index 4c47f12ba0..3551aa1c31 100644
--- a/src/Umbraco.Core/Constants-AppSettings.cs
+++ b/src/Umbraco.Core/Constants-AppSettings.cs
@@ -41,32 +41,27 @@ namespace Umbraco.Core
///
/// Gets the path to umbraco's root directory (/umbraco by default).
///
- public const string Path = "Umbraco.Core.Path";
+ public const string UmbracoPath = "Umbraco.Core.Path";
///
/// The reserved urls from web.config.
///
public const string ReservedUrls = "Umbraco.Core.ReservedUrls";
-
- ///
- /// The path of backoffice.
- ///
- public const string UmbracoPath = "umbracoPath";
-
+
///
/// The path of the stylesheet folder.
///
- public const string UmbracoCssPath = "umbracoCssPath";
+ public const string UmbracoCssPath = "Umbraco.Web.CssPath";
///
/// The path of script folder.
///
- public const string UmbracoScriptsPath = "umbracoScriptsPath";
+ public const string UmbracoScriptsPath = "Umbraco.Core.ScriptsPath";
///
/// The path of media folder.
///
- public const string UmbracoMediaPath = "umbracoMediaPath";
+ public const string UmbracoMediaPath = "Umbraco.Core.MediaPath";
///
/// The reserved paths from web.config
@@ -115,6 +110,11 @@ namespace Umbraco.Core
///
public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer";
+ ///
+ /// Gets the path to the razor file used when no published content is available.
+ ///
+ public const string NoNodesViewPath = "Umbraco.Core.NoNodesViewPath";
+
///
/// Debug specific web.config AppSetting keys for Umbraco
///
diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs
new file mode 100644
index 0000000000..86a02affb6
--- /dev/null
+++ b/src/Umbraco.Core/Constants-Configuration.cs
@@ -0,0 +1,21 @@
+namespace Umbraco.Core
+{
+ public static partial class Constants
+ {
+ public static class Configuration
+ {
+ ///
+ /// Case insensitive prefix for all configurations
+ ///
+ ///
+ /// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}}
+ ///
+ public const string ConfigPrefix = "Umbraco:CMS:";
+ public const string ConfigSecurityPrefix = ConfigPrefix+"Security:";
+ public const string ConfigGlobalPrefix = ConfigPrefix + "Global:";
+ public const string ConfigModelsBuilderPrefix = ConfigPrefix+"ModelsBuilder:";
+ public const string ConfigRuntimeMinification = ConfigPrefix+"RuntimeMinification";
+ public const string ConfigRuntimeMinificationVersion = ConfigRuntimeMinification+":Version";
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Constants-ModelsBuilder.cs b/src/Umbraco.Core/Constants-ModelsBuilder.cs
new file mode 100644
index 0000000000..28e70ed383
--- /dev/null
+++ b/src/Umbraco.Core/Constants-ModelsBuilder.cs
@@ -0,0 +1,17 @@
+namespace Umbraco.Core
+{
+ ///
+ /// Defines constants.
+ ///
+ public static partial class Constants
+ {
+ ///
+ /// Defines constants for ModelsBuilder.
+ ///
+ public static class ModelsBuilder
+ {
+
+ public const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Constants-Security.cs b/src/Umbraco.Core/Constants-Security.cs
index ae5741f0ef..b90a741f91 100644
--- a/src/Umbraco.Core/Constants-Security.cs
+++ b/src/Umbraco.Core/Constants-Security.cs
@@ -25,8 +25,10 @@
public const string UnknownUserName = "SYTEM";
public const string AdminGroupAlias = "admin";
+ public const string EditorGroupAlias = "editor";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
+ public const string WriterGroupAlias = "writer";
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs
index abb92298f4..837db01b63 100644
--- a/src/Umbraco.Core/Constants-System.cs
+++ b/src/Umbraco.Core/Constants-System.cs
@@ -1,4 +1,4 @@
-namespace Umbraco.Core
+ namespace Umbraco.Core
{
public static partial class Constants
{
diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
index 4574934939..26e66c8cfc 100644
--- a/src/Umbraco.Core/Constants-Web.cs
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -35,6 +35,11 @@
///
public const string AngularHeadername = "X-UMB-XSRF-TOKEN";
+ ///
+ /// The route name of the page shown when Umbraco has no published content.
+ ///
+ public const string NoContentRouteName = "umbraco-no-content";
+
///
/// The claim type for the ASP.NET Identity security stamp
///
diff --git a/src/Umbraco.Core/ContentApps/ContentEditorContentAppFactory.cs b/src/Umbraco.Core/ContentApps/ContentEditorContentAppFactory.cs
index add7e2f16a..467bc6c29f 100644
--- a/src/Umbraco.Core/ContentApps/ContentEditorContentAppFactory.cs
+++ b/src/Umbraco.Core/ContentApps/ContentEditorContentAppFactory.cs
@@ -7,7 +7,7 @@ using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.ContentApps
{
- internal class ContentEditorContentAppFactory : IContentAppFactory
+ public class ContentEditorContentAppFactory : IContentAppFactory
{
// see note on ContentApp
internal const int Weight = -100;
diff --git a/src/Umbraco.Core/ContentApps/ListViewContentAppFactory.cs b/src/Umbraco.Core/ContentApps/ListViewContentAppFactory.cs
index 3e0dea0f5e..d66de3b238 100644
--- a/src/Umbraco.Core/ContentApps/ListViewContentAppFactory.cs
+++ b/src/Umbraco.Core/ContentApps/ListViewContentAppFactory.cs
@@ -10,7 +10,7 @@ using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.ContentApps
{
- internal class ListViewContentAppFactory : IContentAppFactory
+ public class ListViewContentAppFactory : IContentAppFactory
{
// see note on ContentApp
private const int Weight = -666;
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/ContentDashboard.cs b/src/Umbraco.Core/Dashboards/ContentDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/ContentDashboard.cs
rename to src/Umbraco.Core/Dashboards/ContentDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/ExamineDashboard.cs b/src/Umbraco.Core/Dashboards/ExamineDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/ExamineDashboard.cs
rename to src/Umbraco.Core/Dashboards/ExamineDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/FormsDashboard.cs b/src/Umbraco.Core/Dashboards/FormsDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/FormsDashboard.cs
rename to src/Umbraco.Core/Dashboards/FormsDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/HealthCheckDashboard.cs b/src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/HealthCheckDashboard.cs
rename to src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/MediaDashboard.cs b/src/Umbraco.Core/Dashboards/MediaDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/MediaDashboard.cs
rename to src/Umbraco.Core/Dashboards/MediaDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/MembersDashboard.cs b/src/Umbraco.Core/Dashboards/MembersDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/MembersDashboard.cs
rename to src/Umbraco.Core/Dashboards/MembersDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/ProfilerDashboard.cs b/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/ProfilerDashboard.cs
rename to src/Umbraco.Core/Dashboards/ProfilerDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/PublishedStatusDashboard.cs b/src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/PublishedStatusDashboard.cs
rename to src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/RedirectUrlDashboard.cs b/src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/RedirectUrlDashboard.cs
rename to src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs
diff --git a/src/Umbraco.Web.BackOffice/Dashboards/SettingsDashboards.cs b/src/Umbraco.Core/Dashboards/SettingsDashboards.cs
similarity index 100%
rename from src/Umbraco.Web.BackOffice/Dashboards/SettingsDashboards.cs
rename to src/Umbraco.Core/Dashboards/SettingsDashboards.cs
diff --git a/src/Umbraco.Web/DefaultEventMessagesFactory.cs b/src/Umbraco.Core/DefaultEventMessagesFactory.cs
similarity index 92%
rename from src/Umbraco.Web/DefaultEventMessagesFactory.cs
rename to src/Umbraco.Core/DefaultEventMessagesFactory.cs
index 39be829a7d..0d53645b5e 100644
--- a/src/Umbraco.Web/DefaultEventMessagesFactory.cs
+++ b/src/Umbraco.Core/DefaultEventMessagesFactory.cs
@@ -3,7 +3,7 @@ using Umbraco.Core.Events;
namespace Umbraco.Web
{
- internal class DefaultEventMessagesFactory : IEventMessagesFactory
+ public class DefaultEventMessagesFactory : IEventMessagesFactory
{
private readonly IEventMessagesAccessor _eventMessagesAccessor;
diff --git a/src/Umbraco.Core/HashGenerator.cs b/src/Umbraco.Core/HashGenerator.cs
index 62be0dacdd..c7fad08089 100644
--- a/src/Umbraco.Core/HashGenerator.cs
+++ b/src/Umbraco.Core/HashGenerator.cs
@@ -41,7 +41,7 @@ namespace Umbraco.Core
public void AddDateTime(DateTime d)
{
- _writer.Write(d.Ticks);;
+ _writer.Write(d.Ticks);
}
public void AddString(string s)
diff --git a/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs
new file mode 100644
index 0000000000..93441f1a47
--- /dev/null
+++ b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs
@@ -0,0 +1,8 @@
+namespace Umbraco.Core.Hosting
+{
+ public interface IApplicationShutdownRegistry
+ {
+ void RegisterObject(IRegisteredObject registeredObject);
+ void UnregisterObject(IRegisteredObject registeredObject);
+ }
+}
diff --git a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
index 1662879cf2..0bdfe5c425 100644
--- a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
+++ b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs
@@ -9,25 +9,38 @@ namespace Umbraco.Core.Hosting
string ApplicationPhysicalPath { get; }
string LocalTempPath { get; }
+
+ ///
+ /// The web application's hosted path
+ ///
+ ///
+ /// In most cases this will return "/" but if the site is hosted in a virtual directory then this will return the virtual directory's path such as "/mysite".
+ /// This value must begin with a "/" and cannot end with "/".
+ ///
string ApplicationVirtualPath { get; }
- int CurrentDomainId { get; }
-
bool IsDebugMode { get; }
+
///
/// Gets a value indicating whether Umbraco is hosted.
///
bool IsHosted { get; }
+
Version IISVersion { get; }
string MapPath(string path);
- string ToAbsolute(string virtualPath, string root);
///
- /// Terminates the current application. The application restarts the next time a request is received for it.
+ /// Maps a virtual path to the application's web root
///
- void LazyRestartApplication();
-
- void RegisterObject(IRegisteredObject registeredObject);
- void UnregisterObject(IRegisteredObject registeredObject);
+ /// The virtual path. Must start with either ~/ or / else an exception is thrown.
+ ///
+ ///
+ /// This maps the virtual path syntax to the web root. For example when hosting in a virtual directory called "site" and the value "~/pages/test" is passed in, it will
+ /// map to "/site/pages/test" where "/site" is the value of .
+ ///
+ ///
+ /// If virtualPath does not start with ~/ or /
+ ///
+ string ToAbsolute(string virtualPath);
}
}
diff --git a/src/Umbraco.Core/HybridEventMessagesAccessor.cs b/src/Umbraco.Core/HybridEventMessagesAccessor.cs
index b2700eb137..82e784e093 100644
--- a/src/Umbraco.Core/HybridEventMessagesAccessor.cs
+++ b/src/Umbraco.Core/HybridEventMessagesAccessor.cs
@@ -3,7 +3,7 @@ using Umbraco.Core.Events;
namespace Umbraco.Web
{
- internal class HybridEventMessagesAccessor : HybridAccessorBase, IEventMessagesAccessor
+ public class HybridEventMessagesAccessor : HybridAccessorBase, IEventMessagesAccessor
{
protected override string ItemKey => "Umbraco.Core.Events.HybridEventMessagesAccessor";
diff --git a/src/Umbraco.Web/HybridUmbracoContextAccessor.cs b/src/Umbraco.Core/HybridUmbracoContextAccessor.cs
similarity index 87%
rename from src/Umbraco.Web/HybridUmbracoContextAccessor.cs
rename to src/Umbraco.Core/HybridUmbracoContextAccessor.cs
index bb8e2d6993..1ad4777460 100644
--- a/src/Umbraco.Web/HybridUmbracoContextAccessor.cs
+++ b/src/Umbraco.Core/HybridUmbracoContextAccessor.cs
@@ -5,7 +5,7 @@ namespace Umbraco.Web
///
/// Implements a hybrid .
///
- internal class HybridUmbracoContextAccessor : HybridAccessorBase, IUmbracoContextAccessor
+ public class HybridUmbracoContextAccessor : HybridAccessorBase, IUmbracoContextAccessor
{
///
/// Initializes a new instance of the class.
diff --git a/src/Umbraco.Core/IO/IIOHelper.cs b/src/Umbraco.Core/IO/IIOHelper.cs
index 11f5c6c565..42ca804f44 100644
--- a/src/Umbraco.Core/IO/IIOHelper.cs
+++ b/src/Umbraco.Core/IO/IIOHelper.cs
@@ -4,15 +4,19 @@ namespace Umbraco.Core.IO
{
public interface IIOHelper
{
- bool ForceNotHosted { get; set; }
-
- char DirSepChar { get; }
string FindFile(string virtualPath);
- string ResolveVirtualUrl(string path);
- string ResolveUrl(string virtualPath);
- Attempt TryResolveUrl(string virtualPath);
- string MapPath(string path);
+ // TODO: This is the same as IHostingEnvironment.ToAbsolute
+ string ResolveUrl(string virtualPath);
+
+ Attempt TryResolveUrl(string virtualPath);
+
+ ///
+ /// Maps a virtual path to a physical path in the content root folder (i.e. www)
+ ///
+ ///
+ ///
+ string MapPath(string path);
///
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
@@ -40,24 +44,6 @@ namespace Umbraco.Core.IO
bool PathStartsWith(string path, string root, char separator);
- ///
- /// Returns the path to the root of the application, by getting the path to where the assembly where this
- /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
- /// even if the assembly is in a /bin/debug or /bin/release folder
- ///
- ///
- string GetRootDirectorySafe();
-
- string GetRootDirectoryBinFolder();
-
- ///
- /// Allows you to overwrite RootDirectory, which would otherwise be resolved
- /// automatically upon application start.
- ///
- /// The supplied path should be the absolute path to the root of the umbraco site.
- ///
- void SetRootDirectory(string rootPath);
-
void EnsurePathExists(string path);
///
@@ -67,14 +53,5 @@ namespace Umbraco.Core.IO
///
string GetRelativePath(string path);
- ///
- /// Gets the root path of the application
- ///
- string Root
- {
- get;
- set; //Only required for unit tests
- }
-
}
}
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
index d5e1335f35..a71a307e01 100644
--- a/src/Umbraco.Core/IO/IOHelper.cs
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.Reflection;
using System.IO;
using System.Linq;
+using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Strings;
@@ -13,54 +14,34 @@ namespace Umbraco.Core.IO
{
private readonly IHostingEnvironment _hostingEnvironment;
- public IOHelper(IHostingEnvironment hostingEnvironment)
+ public IOHelper(IHostingEnvironment hostingEnvironment, IGlobalSettings globalSettings)
{
- _hostingEnvironment = hostingEnvironment;
+ _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
}
- ///
- /// Gets or sets a value forcing Umbraco to consider it is non-hosted.
- ///
- /// This should always be false, unless unit testing.
- public bool ForceNotHosted { get; set; }
-
- private static string _rootDir = "";
-
// static compiled regex for faster performance
//private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
-
- public char DirSepChar => Path.DirectorySeparatorChar;
-
//helper to try and match the old path to a new virtual one
public string FindFile(string virtualPath)
{
string retval = virtualPath;
if (virtualPath.StartsWith("~"))
- retval = virtualPath.Replace("~", Root);
+ retval = virtualPath.Replace("~", _hostingEnvironment.ApplicationVirtualPath);
- if (virtualPath.StartsWith("/") && virtualPath.StartsWith(Root) == false)
- retval = Root + "/" + virtualPath.TrimStart('/');
+ if (virtualPath.StartsWith("/") && virtualPath.StartsWith(_hostingEnvironment.ApplicationVirtualPath) == false)
+ retval = _hostingEnvironment.ApplicationVirtualPath + "/" + virtualPath.TrimStart('/');
return retval;
}
- public string ResolveVirtualUrl(string path)
- {
- if (string.IsNullOrWhiteSpace(path)) return path;
- return path.StartsWith("~/") ? ResolveUrl(path) : path;
- }
-
- //Replaces tildes with the root dir
+ // TODO: This is the same as IHostingEnvironment.ToAbsolute
public string ResolveUrl(string virtualPath)
{
- if (virtualPath.StartsWith("~"))
- return virtualPath.Replace("~", Root).Replace("//", "/");
- else if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
- return virtualPath;
- else
- return _hostingEnvironment.ToAbsolute(virtualPath, Root);
+ if (string.IsNullOrWhiteSpace(virtualPath)) return virtualPath;
+ return _hostingEnvironment.ToAbsolute(virtualPath);
+
}
public Attempt TryResolveUrl(string virtualPath)
@@ -68,10 +49,11 @@ namespace Umbraco.Core.IO
try
{
if (virtualPath.StartsWith("~"))
- return Attempt.Succeed(virtualPath.Replace("~", Root).Replace("//", "/"));
+ return Attempt.Succeed(virtualPath.Replace("~", _hostingEnvironment.ApplicationVirtualPath).Replace("//", "/"));
if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
return Attempt.Succeed(virtualPath);
- return Attempt.Succeed(_hostingEnvironment.ToAbsolute(virtualPath, Root));
+
+ return Attempt.Succeed(_hostingEnvironment.ToAbsolute(virtualPath));
}
catch (Exception ex)
{
@@ -95,20 +77,17 @@ namespace Umbraco.Core.IO
if (_hostingEnvironment.IsHosted)
{
- var result = (String.IsNullOrEmpty(path) == false && (path.StartsWith("~") || path.StartsWith(Root)))
- ? _hostingEnvironment.MapPath(path)
+ var result = (!string.IsNullOrEmpty(path) && (path.StartsWith("~") || path.StartsWith(_hostingEnvironment.ApplicationVirtualPath)))
+ ? _hostingEnvironment.MapPath(path)
: _hostingEnvironment.MapPath("~/" + path.TrimStart('/'));
if (result != null) return result;
-
-
}
-
-
- var root = GetRootDirectorySafe();
- var newPath = path.TrimStart('~', '/').Replace('/', DirSepChar);
- var retval = root + DirSepChar.ToString(CultureInfo.InvariantCulture) + newPath;
+ var dirSepChar = Path.DirectorySeparatorChar;
+ var root = Assembly.GetExecutingAssembly().GetRootDirectorySafe();
+ var newPath = path.TrimStart('~', '/').Replace('/', dirSepChar);
+ var retval = root + dirSepChar.ToString(CultureInfo.InvariantCulture) + newPath;
return retval;
}
@@ -142,7 +121,7 @@ namespace Umbraco.Core.IO
// TODO: what's below is dirty, there are too many ways to get the root dir, etc.
// not going to fix everything today
- var mappedRoot = MapPath(Root);
+ var mappedRoot = MapPath(_hostingEnvironment.ApplicationVirtualPath);
if (filePath.StartsWith(mappedRoot) == false)
filePath = MapPath(filePath);
@@ -186,71 +165,6 @@ namespace Umbraco.Core.IO
return path[root.Length] == separator;
}
- ///
- /// Returns the path to the root of the application, by getting the path to where the assembly where this
- /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
- /// even if the assembly is in a /bin/debug or /bin/release folder
- ///
- ///
- public string GetRootDirectorySafe()
- {
- if (String.IsNullOrEmpty(_rootDir) == false)
- {
- return _rootDir;
- }
-
- var codeBase = Assembly.GetExecutingAssembly().CodeBase;
- var uri = new Uri(codeBase);
- var path = uri.LocalPath;
- var baseDirectory = Path.GetDirectoryName(path);
- if (String.IsNullOrEmpty(baseDirectory))
- throw new Exception("No root directory could be resolved. Please ensure that your Umbraco solution is correctly configured.");
-
- _rootDir = baseDirectory.Contains("bin")
- ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
- : baseDirectory;
-
- return _rootDir;
- }
-
- public string GetRootDirectoryBinFolder()
- {
- string binFolder = String.Empty;
- if (String.IsNullOrEmpty(_rootDir))
- {
- binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory.FullName;
- return binFolder;
- }
-
- binFolder = Path.Combine(GetRootDirectorySafe(), "bin");
-
- // do this all the time (no #if DEBUG) because Umbraco release
- // can be used in tests by an app (eg Deploy) being debugged
- var debugFolder = Path.Combine(binFolder, "debug");
- if (Directory.Exists(debugFolder))
- return debugFolder;
-
- var releaseFolder = Path.Combine(binFolder, "release");
- if (Directory.Exists(releaseFolder))
- return releaseFolder;
-
- if (Directory.Exists(binFolder))
- return binFolder;
-
- return _rootDir;
- }
-
- ///
- /// Allows you to overwrite RootDirectory, which would otherwise be resolved
- /// automatically upon application start.
- ///
- /// The supplied path should be the absolute path to the root of the umbraco site.
- ///
- public void SetRootDirectory(string rootPath)
- {
- _rootDir = rootPath;
- }
-
public void EnsurePathExists(string path)
{
var absolutePath = MapPath(path);
@@ -267,7 +181,7 @@ namespace Umbraco.Core.IO
{
if (path.IsFullPath())
{
- var rootDirectory = GetRootDirectorySafe();
+ var rootDirectory = MapPath("~");
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
path = relativePath;
}
@@ -275,27 +189,5 @@ namespace Umbraco.Core.IO
return PathUtility.EnsurePathIsApplicationRootPrefixed(path);
}
- private string _root;
-
- ///
- /// Gets the root path of the application
- ///
- public string Root
- {
- get
- {
- if (_root != null) return _root;
-
- var appPath = _hostingEnvironment.ApplicationVirtualPath;
- // ReSharper disable once ConditionIsAlwaysTrueOrFalse
- if (appPath == null || appPath == "/") appPath = string.Empty;
-
- _root = appPath;
-
- return _root;
- }
- //Only required for unit tests
- set => _root = value;
- }
}
}
diff --git a/src/Umbraco.Core/IO/IOHelperExtensions.cs b/src/Umbraco.Core/IO/IOHelperExtensions.cs
index 64b57e7dc1..6912974196 100644
--- a/src/Umbraco.Core/IO/IOHelperExtensions.cs
+++ b/src/Umbraco.Core/IO/IOHelperExtensions.cs
@@ -5,6 +5,19 @@ namespace Umbraco.Core.IO
{
public static class IOHelperExtensions
{
+ ///
+ /// Will resolve a virtual path URL to an absolute path, else if it is not a virtual path (i.e. starts with ~/) then
+ /// it will just return the path as-is (relative).
+ ///
+ ///
+ ///
+ ///
+ public static string ResolveRelativeOrVirtualUrl(this IIOHelper ioHelper, string path)
+ {
+ if (string.IsNullOrWhiteSpace(path)) return path;
+ return path.StartsWith("~/") ? ioHelper.ResolveUrl(path) : path;
+ }
+
///
/// Tries to create a directory.
///
@@ -35,5 +48,7 @@ namespace Umbraco.Core.IO
{
return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8);
}
+
+
}
}
diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
index 24284fec98..403557958a 100644
--- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs
+++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
@@ -59,7 +59,8 @@ namespace Umbraco.Core.IO
if (Path.IsPathRooted(rootPath) == false)
{
// but the test suite App.config cannot really "root" anything so we have to do it here
- var localRoot = _ioHelper.GetRootDirectorySafe();
+ // TODO: This will map to the web content root (www) not the web app root, is that what we want? Else we need to use IHostingEnvironment.ApplicationPhysicalPath
+ var localRoot = _ioHelper.MapPath("~");
rootPath = Path.Combine(localRoot, rootPath);
}
diff --git a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs b/src/Umbraco.Core/Logging/ConsoleLogger.cs
similarity index 98%
rename from src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs
rename to src/Umbraco.Core/Logging/ConsoleLogger.cs
index 53d6078e4b..275b8d988b 100644
--- a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs
+++ b/src/Umbraco.Core/Logging/ConsoleLogger.cs
@@ -1,7 +1,6 @@
using System;
-using Umbraco.Core.Logging;
-namespace Umbraco.Tests.TestHelpers
+namespace Umbraco.Core.Logging
{
public class ConsoleLogger : ILogger
{
diff --git a/src/Umbraco.Core/Logging/ILogger.cs b/src/Umbraco.Core/Logging/ILogger.cs
index 4f49d0b3b4..fe7d798ebf 100644
--- a/src/Umbraco.Core/Logging/ILogger.cs
+++ b/src/Umbraco.Core/Logging/ILogger.cs
@@ -2,6 +2,7 @@
namespace Umbraco.Core.Logging
{
+
///
/// Defines the logging service.
///
diff --git a/src/Umbraco.Web/Macros/IMacroRenderer.cs b/src/Umbraco.Core/Macros/IMacroRenderer.cs
similarity index 100%
rename from src/Umbraco.Web/Macros/IMacroRenderer.cs
rename to src/Umbraco.Core/Macros/IMacroRenderer.cs
diff --git a/src/Umbraco.Core/Macros/MacroContent.cs b/src/Umbraco.Core/Macros/MacroContent.cs
new file mode 100644
index 0000000000..60dfb9210d
--- /dev/null
+++ b/src/Umbraco.Core/Macros/MacroContent.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Umbraco.Web.Macros
+{
+ // represents the content of a macro
+ public class MacroContent
+ {
+ // gets or sets the text content
+ public string Text { get; set; }
+
+ // gets or sets the date the content was generated
+ public DateTime Date { get; set; } = DateTime.Now;
+
+ // a value indicating whether the content is empty
+ public bool IsEmpty => Text is null;
+
+ // gets an empty macro content
+ public static MacroContent Empty { get; } = new MacroContent();
+ }
+}
diff --git a/src/Umbraco.Web/Macros/MacroModel.cs b/src/Umbraco.Core/Macros/MacroModel.cs
similarity index 91%
rename from src/Umbraco.Web/Macros/MacroModel.cs
rename to src/Umbraco.Core/Macros/MacroModel.cs
index dd9a73b147..6b5013115a 100644
--- a/src/Umbraco.Web/Macros/MacroModel.cs
+++ b/src/Umbraco.Core/Macros/MacroModel.cs
@@ -20,8 +20,6 @@ namespace Umbraco.Web.Macros
///
public string Alias { get; set; }
- public MacroTypes MacroType { get; set; }
-
public string MacroSource { get; set; }
public int CacheDuration { get; set; }
@@ -46,7 +44,6 @@ namespace Umbraco.Web.Macros
Id = macro.Id;
Name = macro.Name;
Alias = macro.Alias;
- MacroType = macro.MacroType;
MacroSource = macro.MacroSource;
CacheDuration = macro.CacheDuration;
CacheByPage = macro.CacheByPage;
@@ -55,8 +52,6 @@ namespace Umbraco.Web.Macros
foreach (var prop in macro.Properties)
Properties.Add(new MacroPropertyModel(prop.Alias, string.Empty, prop.EditorAlias));
-
- MacroType = macro.MacroType;
}
}
}
diff --git a/src/Umbraco.Web/Macros/MacroPropertyModel.cs b/src/Umbraco.Core/Macros/MacroPropertyModel.cs
similarity index 100%
rename from src/Umbraco.Web/Macros/MacroPropertyModel.cs
rename to src/Umbraco.Core/Macros/MacroPropertyModel.cs
diff --git a/src/Umbraco.Core/Manifest/IManifestParser.cs b/src/Umbraco.Core/Manifest/IManifestParser.cs
index eeb0c756f6..3eec7007b3 100644
--- a/src/Umbraco.Core/Manifest/IManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/IManifestParser.cs
@@ -17,7 +17,5 @@ namespace Umbraco.Core.Manifest
/// Parses a manifest.
///
PackageManifest ParseManifest(string text);
-
- IEnumerable ParseGridEditors(string text);
}
}
diff --git a/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs b/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs
index 903efe2897..298047754c 100644
--- a/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs
+++ b/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs
@@ -136,14 +136,14 @@ namespace Umbraco.Core.Manifest
// else
// content app can be displayed
- return _app ?? (_app = new ContentApp
+ return _app ??= new ContentApp
{
Alias = _definition.Alias,
Name = _definition.Name,
Icon = _definition.Icon,
- View = _ioHelper.ResolveVirtualUrl(_definition.View),
+ View = _ioHelper.ResolveRelativeOrVirtualUrl(_definition.View),
Weight = _definition.Weight
- });
+ };
}
private class ShowRule
diff --git a/src/Umbraco.Core/Manifest/ManifestWatcher.cs b/src/Umbraco.Core/Manifest/ManifestWatcher.cs
index 8d81ac3de5..23caac3a1b 100644
--- a/src/Umbraco.Core/Manifest/ManifestWatcher.cs
+++ b/src/Umbraco.Core/Manifest/ManifestWatcher.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using Umbraco.Core.Hosting;
using Umbraco.Core.Logging;
+using Umbraco.Net;
namespace Umbraco.Core.Manifest
{
@@ -13,13 +14,13 @@ namespace Umbraco.Core.Manifest
private static volatile bool _isRestarting;
private readonly ILogger _logger;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
private readonly List _fws = new List();
- public ManifestWatcher(ILogger logger, IHostingEnvironment hostingEnvironment)
+ public ManifestWatcher(ILogger logger, IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _hostingEnvironment = hostingEnvironment;
+ _umbracoApplicationLifetime = umbracoApplicationLifetime;
}
public void Start(params string[] packageFolders)
@@ -57,7 +58,7 @@ namespace Umbraco.Core.Manifest
_isRestarting = true;
_logger.Info("Manifest has changed, app pool is restarting ({Path})", e.FullPath);
- _hostingEnvironment.LazyRestartApplication();
+ _umbracoApplicationLifetime.Restart();
Dispose(); // uh? if the app restarts then this should be disposed anyways?
}
}
diff --git a/src/Umbraco.Core/Models/IImageUrlGenerator.cs b/src/Umbraco.Core/Media/IImageUrlGenerator.cs
similarity index 66%
rename from src/Umbraco.Core/Models/IImageUrlGenerator.cs
rename to src/Umbraco.Core/Media/IImageUrlGenerator.cs
index 0dc2933fd9..f9e67cdd2b 100644
--- a/src/Umbraco.Core/Models/IImageUrlGenerator.cs
+++ b/src/Umbraco.Core/Media/IImageUrlGenerator.cs
@@ -1,4 +1,6 @@
-namespace Umbraco.Core.Models
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.Media
{
public interface IImageUrlGenerator
{
diff --git a/src/Umbraco.Core/Models/DeepCloneHelper.cs b/src/Umbraco.Core/Models/DeepCloneHelper.cs
index 6470de912b..453b455d4b 100644
--- a/src/Umbraco.Core/Models/DeepCloneHelper.cs
+++ b/src/Umbraco.Core/Models/DeepCloneHelper.cs
@@ -81,9 +81,10 @@ namespace Umbraco.Core.Models
if (propertyInfo.PropertyType.IsGenericType
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
- || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
+ || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)
+ || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>)))
{
- //if it is a IEnumerable<>, IList or ICollection<> we'll use a List<>
+ //if it is a IEnumerable<>, IReadOnlyCollection, IList or ICollection<> we'll use a List<> since it implements them all
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
}
diff --git a/src/Umbraco.Core/Models/IKeyValue.cs b/src/Umbraco.Core/Models/IKeyValue.cs
new file mode 100644
index 0000000000..6025d4d37b
--- /dev/null
+++ b/src/Umbraco.Core/Models/IKeyValue.cs
@@ -0,0 +1,12 @@
+using System;
+using Umbraco.Core.Models.Entities;
+
+namespace Umbraco.Core.Models
+{
+ public interface IKeyValue : IEntity
+ {
+ string Identifier { get; set; }
+
+ string Value { get; set; }
+ }
+}
diff --git a/src/Umbraco.Core/Models/IMacro.cs b/src/Umbraco.Core/Models/IMacro.cs
index c3d37b0700..9d1c47154c 100644
--- a/src/Umbraco.Core/Models/IMacro.cs
+++ b/src/Umbraco.Core/Models/IMacro.cs
@@ -58,22 +58,10 @@ namespace Umbraco.Core.Models
[DataMember]
string MacroSource { get; set; }
- ///
- /// Gets or set the macro type
- ///
- [DataMember]
- MacroTypes MacroType { get; set; }
-
///
/// Gets or sets a list of Macro Properties
///
[DataMember]
MacroPropertyCollection Properties { get; }
-
- /////
- ///// Returns an enum based on the properties on the Macro
- /////
- /////
- //MacroTypes MacroType();
}
}
diff --git a/src/Umbraco.Core/Models/KeyValue.cs b/src/Umbraco.Core/Models/KeyValue.cs
new file mode 100644
index 0000000000..2d47fcbfb3
--- /dev/null
+++ b/src/Umbraco.Core/Models/KeyValue.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Runtime.Serialization;
+using Umbraco.Core.Models.Entities;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Implements .
+ ///
+ [Serializable]
+ [DataContract(IsReference = true)]
+ public class KeyValue : EntityBase, IKeyValue, IEntity
+ {
+ private string _identifier;
+ private string _value;
+
+ ///
+ public string Identifier
+ {
+ get => _identifier;
+ set => SetPropertyValueAndDetectChanges(value, ref _identifier, nameof(Identifier));
+ }
+
+ ///
+ public string Value
+ {
+ get => _value;
+ set => SetPropertyValueAndDetectChanges(value, ref _value, nameof(Value));
+ }
+
+ bool IEntity.HasIdentity => !string.IsNullOrEmpty(Identifier);
+ }
+}
diff --git a/src/Umbraco.Core/Models/MacroTypes.cs b/src/Umbraco.Core/Models/MacroTypes.cs
deleted file mode 100644
index 5f8440845d..0000000000
--- a/src/Umbraco.Core/Models/MacroTypes.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Runtime.Serialization;
-
-namespace Umbraco.Core.Models
-{
- ///
- /// Enum for the various types of Macros
- ///
- [Serializable]
- [DataContract(IsReference = true)]
- public enum MacroTypes
- {
- [EnumMember]
- Unknown = 4,
- [EnumMember]
- PartialView = 7
- }
-}
diff --git a/src/Umbraco.Core/Models/PartialViewMacroModel.cs b/src/Umbraco.Core/Models/PartialViewMacroModel.cs
index 9964877cba..f3272644f4 100644
--- a/src/Umbraco.Core/Models/PartialViewMacroModel.cs
+++ b/src/Umbraco.Core/Models/PartialViewMacroModel.cs
@@ -6,7 +6,7 @@ namespace Umbraco.Web.Models
///
/// The model used when rendering Partial View Macros
///
- public class PartialViewMacroModel
+ public class PartialViewMacroModel : IContentModel
{
public PartialViewMacroModel(IPublishedContent page,
diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
index 7c207c23c0..79c7f824fc 100644
--- a/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/PublishedValueFallback.cs
@@ -111,7 +111,7 @@ namespace Umbraco.Web.Models.PublishedContent
var propertyType = content.ContentType.GetPropertyType(alias);
if (propertyType != null)
{
- _variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
+ _variationContextAccessor.ContextualizeVariation(propertyType.Variations, content.Id, ref culture, ref segment);
noValueProperty = content.GetProperty(alias);
}
@@ -168,7 +168,7 @@ namespace Umbraco.Web.Models.PublishedContent
{
culture = null;
segment = null;
- _variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
+ _variationContextAccessor.ContextualizeVariation(propertyType.Variations, content.Id, ref culture, ref segment);
}
property = content?.GetProperty(alias);
diff --git a/src/Umbraco.Core/Models/PublishedContent/VariationContext.cs b/src/Umbraco.Core/Models/PublishedContent/VariationContext.cs
index b83002fdce..424fc7c4a8 100644
--- a/src/Umbraco.Core/Models/PublishedContent/VariationContext.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/VariationContext.cs
@@ -23,5 +23,12 @@
/// Gets the segment.
///
public string Segment { get; }
+
+ ///
+ /// Gets the segment for the content item
+ ///
+ ///
+ ///
+ public virtual string GetSegment(int contentId) => Segment;
}
}
diff --git a/src/Umbraco.Core/Models/PublishedContent/VariationContextAccessorExtensions.cs b/src/Umbraco.Core/Models/PublishedContent/VariationContextAccessorExtensions.cs
index 6710d79cc6..a387ea87b8 100644
--- a/src/Umbraco.Core/Models/PublishedContent/VariationContextAccessorExtensions.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/VariationContextAccessorExtensions.cs
@@ -3,13 +3,32 @@
public static class VariationContextAccessorExtensions
{
public static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, ref string culture, ref string segment)
+ => variationContextAccessor.ContextualizeVariation(variations, null, ref culture, ref segment);
+
+ public static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, int contentId, ref string culture, ref string segment)
+ => variationContextAccessor.ContextualizeVariation(variations, (int?)contentId, ref culture, ref segment);
+
+ private static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, int? contentId, ref string culture, ref string segment)
{
if (culture != null && segment != null) return;
// use context values
var publishedVariationContext = variationContextAccessor?.VariationContext;
if (culture == null) culture = variations.VariesByCulture() ? publishedVariationContext?.Culture : "";
- if (segment == null) segment = variations.VariesBySegment() ? publishedVariationContext?.Segment : "";
+
+ if (segment == null)
+ {
+ if (variations.VariesBySegment())
+ {
+ segment = contentId == null
+ ? publishedVariationContext?.Segment
+ : publishedVariationContext?.GetSegment(contentId.Value);
+ }
+ else
+ {
+ segment = "";
+ }
+ }
}
}
}
diff --git a/src/Umbraco.Core/Models/RelationType.cs b/src/Umbraco.Core/Models/RelationType.cs
index 28290685c2..4c676feed6 100644
--- a/src/Umbraco.Core/Models/RelationType.cs
+++ b/src/Umbraco.Core/Models/RelationType.cs
@@ -31,8 +31,6 @@ namespace Umbraco.Core.Models
_childObjectType = childObjectType;
}
-
-
///
/// Gets or sets the Name of the RelationType
///
diff --git a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs
new file mode 100644
index 0000000000..a032720d46
--- /dev/null
+++ b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Umbraco.Net
+{
+ // TODO: This shouldn't be in this namespace?
+ public interface IUmbracoApplicationLifetime
+ {
+ ///
+ /// A value indicating whether the application is restarting after the current request.
+ ///
+ bool IsRestarting { get; }
+ ///
+ /// Terminates the current application. The application restarts the next time a request is received for it.
+ ///
+ void Restart();
+
+ event EventHandler ApplicationInit;
+ }
+
+
+ public interface IUmbracoApplicationLifetimeManager
+ {
+ void InvokeApplicationInit();
+ }
+}
diff --git a/src/Umbraco.Core/Net/IUserAgentProvider.cs b/src/Umbraco.Core/Net/IUserAgentProvider.cs
new file mode 100644
index 0000000000..14246ea99e
--- /dev/null
+++ b/src/Umbraco.Core/Net/IUserAgentProvider.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Net
+{
+ public interface IUserAgentProvider
+ {
+ string GetUserAgent();
+ }
+}
diff --git a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs
index 7425f64727..9a976bea41 100644
--- a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs
+++ b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs
@@ -7,7 +7,7 @@ using Umbraco.Core.Services;
namespace Umbraco.Core.Packaging
{
- public class ConflictingPackageData
+ public class ConflictingPackageData
{
private readonly IMacroService _macroService;
private readonly IFileService _fileService;
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Packaging
return stylesheetNodes
.Select(n =>
{
- var xElement = n.Element("Name") ?? n.Element("name"); ;
+ var xElement = n.Element("Name") ?? n.Element("name");
if (xElement == null)
throw new FormatException("Missing \"Name\" element");
diff --git a/src/Umbraco.Core/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Packaging/PackageDefinition.cs
index 11bf26c579..29a1919a2b 100644
--- a/src/Umbraco.Core/Packaging/PackageDefinition.cs
+++ b/src/Umbraco.Core/Packaging/PackageDefinition.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models.Packaging
///
/// This is used only for conversions and will not 'get' a PackageDefinition from the repository with a valid ID
///
- internal static PackageDefinition FromCompiledPackage(CompiledPackage compiled)
+ public static PackageDefinition FromCompiledPackage(CompiledPackage compiled)
{
return new PackageDefinition
{
diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs
index a2a30f3a06..2c5b964518 100644
--- a/src/Umbraco.Core/Packaging/PackagesRepository.cs
+++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Packaging
{
var packagesXml = EnsureStorage(out _);
if (packagesXml?.Root == null)
- yield break;;
+ yield break;
foreach (var packageXml in packagesXml.Root.Elements("package"))
yield return _parser.ToPackageDefinition(packageXml);
@@ -518,7 +518,6 @@ namespace Umbraco.Core.Packaging
private XElement GetStylesheetXml(string name, bool includeProperties)
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(name));
-;
var sts = _fileService.GetStylesheetByName(name);
if (sts == null) return null;
var stylesheetXml = new XElement("Stylesheet");
diff --git a/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs
new file mode 100644
index 0000000000..0eb2b27eb0
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs
@@ -0,0 +1,8 @@
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.Persistence.Repositories
+{
+ public interface IKeyValueRepository : IReadRepository, IWriteRepository
+ {
+ }
+}
diff --git a/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs
index 29ae581459..0d1a8764ae 100644
--- a/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs
@@ -20,8 +20,24 @@ namespace Umbraco.Core.Persistence.Repositories
///
///
///
+ [Obsolete("This method will be removed in future versions. Please use ExistsByUserName instead.")]
bool Exists(string username);
+ ///
+ /// Checks if a user with the username exists
+ ///
+ ///
+ ///
+ bool ExistsByUserName(string username);
+
+
+ ///
+ /// Checks if a user with the login exists
+ ///
+ ///
+ ///
+ bool ExistsByLogin(string login);
+
///
/// Gets a list of objects associated with a given group
///
diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs
index 84ee8c314b..03ce0c066a 100644
--- a/src/Umbraco.Core/PublishedContentExtensions.cs
+++ b/src/Umbraco.Core/PublishedContentExtensions.cs
@@ -149,11 +149,11 @@ namespace Umbraco.Core
}
public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService,
- IUmbracoSettingsSection umbracoSettingsSection, int templateId)
+ IWebRoutingSettings webRoutingSettings, int templateId)
{
return content.IsAllowedTemplate(contentTypeService,
- umbracoSettingsSection.WebRouting.DisableAlternativeTemplates,
- umbracoSettingsSection.WebRouting.ValidateAlternativeTemplates, templateId);
+ webRoutingSettings.DisableAlternativeTemplates,
+ webRoutingSettings.ValidateAlternativeTemplates, templateId);
}
public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService, bool disableAlternativeTemplates, bool validateAlternativeTemplates, int templateId)
diff --git a/src/Umbraco.Core/Routing/AliasUrlProvider.cs b/src/Umbraco.Core/Routing/AliasUrlProvider.cs
index c9cc3d5156..e71de2f6c6 100644
--- a/src/Umbraco.Core/Routing/AliasUrlProvider.cs
+++ b/src/Umbraco.Core/Routing/AliasUrlProvider.cs
@@ -14,13 +14,13 @@ namespace Umbraco.Web.Routing
public class AliasUrlProvider : IUrlProvider
{
private readonly IGlobalSettings _globalSettings;
- private readonly IRequestHandlerSection _requestConfig;
+ private readonly IRequestHandlerSettings _requestConfig;
private readonly ISiteDomainHelper _siteDomainHelper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly UriUtility _uriUtility;
private readonly IPublishedValueFallback _publishedValueFallback;
- public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSection requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor)
+ public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSettings requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor)
{
_globalSettings = globalSettings;
_requestConfig = requestConfig;
diff --git a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
similarity index 79%
rename from src/Umbraco.Web/Routing/ContentFinderByIdPath.cs
rename to src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
index bf7d5ef7c4..4b58832e8e 100644
--- a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
@@ -16,14 +16,14 @@ namespace Umbraco.Web.Routing
public class ContentFinderByIdPath : IContentFinder
{
private readonly ILogger _logger;
- private readonly IHttpContextAccessor _httpContextAccessor;
- private readonly IWebRoutingSection _webRoutingSection;
+ private readonly IRequestAccessor _requestAccessor;
+ private readonly IWebRoutingSettings _webRoutingSettings;
- public ContentFinderByIdPath(IWebRoutingSection webRoutingSection, ILogger logger, IHttpContextAccessor httpContextAccessor)
+ public ContentFinderByIdPath(IWebRoutingSettings webRoutingSettings, ILogger logger, IRequestAccessor requestAccessor)
{
- _webRoutingSection = webRoutingSection ?? throw new System.ArgumentNullException(nameof(webRoutingSection));
+ _webRoutingSettings = webRoutingSettings ?? throw new System.ArgumentNullException(nameof(webRoutingSettings));
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
- _httpContextAccessor = httpContextAccessor;
+ _requestAccessor = requestAccessor;
}
///
@@ -35,7 +35,7 @@ namespace Umbraco.Web.Routing
{
if (frequest.UmbracoContext != null && frequest.UmbracoContext.InPreviewMode == false
- && _webRoutingSection.DisableFindContentByIdPath)
+ && _webRoutingSettings.DisableFindContentByIdPath)
return false;
IPublishedContent node = null;
@@ -56,12 +56,14 @@ namespace Umbraco.Web.Routing
if (node != null)
{
- var httpContext = _httpContextAccessor.GetRequiredHttpContext();
+
+ var cultureFromQuerystring = _requestAccessor.GetQueryStringValue("culture");
+
//if we have a node, check if we have a culture in the query string
- if (httpContext.Request.QueryString.ContainsKey("culture"))
+ if (!string.IsNullOrEmpty(cultureFromQuerystring))
{
//we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though
- frequest.Culture = CultureInfo.GetCultureInfo(httpContext.Request.QueryString["culture"]);
+ frequest.Culture = CultureInfo.GetCultureInfo(cultureFromQuerystring);
}
frequest.PublishedContent = node;
diff --git a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs
similarity index 69%
rename from src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs
rename to src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs
index fb79e13dbc..16d7a0c4cf 100644
--- a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs
@@ -1,4 +1,5 @@
-namespace Umbraco.Web.Routing
+
+namespace Umbraco.Web.Routing
{
///
/// This looks up a document by checking for the umbPageId of a request/query string
@@ -9,17 +10,17 @@
///
public class ContentFinderByPageIdQuery : IContentFinder
{
- private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly IRequestAccessor _requestAccessor;
- public ContentFinderByPageIdQuery(IHttpContextAccessor httpContextAccessor)
+ public ContentFinderByPageIdQuery(IRequestAccessor requestAccessor)
{
- _httpContextAccessor = httpContextAccessor;
+ _requestAccessor = requestAccessor;
}
public bool TryFindContent(IPublishedRequest frequest)
{
int pageId;
- if (int.TryParse(_httpContextAccessor.GetRequiredHttpContext().Request["umbPageID"], out pageId))
+ if (int.TryParse(_requestAccessor.GetRequestValue("umbPageID"), out pageId))
{
var doc = frequest.UmbracoContext.Content.GetById(pageId);
diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
index 933ab47150..7bcea4681e 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
@@ -17,15 +17,16 @@ namespace Umbraco.Web.Routing
public class ContentFinderByUrlAndTemplate : ContentFinderByUrl
{
private readonly IFileService _fileService;
- private readonly IUmbracoSettingsSection _umbracoSettingsSection;
- private readonly IContentTypeService _contentTypeService;
- public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IUmbracoSettingsSection umbracoSettingsSection, IContentTypeService contentTypeService)
+ private readonly IContentTypeService _contentTypeService;
+ private readonly IWebRoutingSettings _webRoutingSettings;
+
+ public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IContentTypeService contentTypeService, IWebRoutingSettings webRoutingSettings)
: base(logger)
{
_fileService = fileService;
- _umbracoSettingsSection = umbracoSettingsSection;
_contentTypeService = contentTypeService;
+ _webRoutingSettings = webRoutingSettings;
}
///
@@ -75,7 +76,7 @@ namespace Umbraco.Web.Routing
}
// IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings
- if (!node.IsAllowedTemplate(_contentTypeService, _umbracoSettingsSection, template.Id))
+ if (!node.IsAllowedTemplate(_contentTypeService, _webRoutingSettings, template.Id))
{
Logger.Warn("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id);
frequest.PublishedContent = null; // clear
diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
index 81102810e8..f56d96b6b3 100644
--- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
+++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs
@@ -12,14 +12,14 @@ namespace Umbraco.Web.Routing
///
public class DefaultUrlProvider : IUrlProvider
{
- private readonly IRequestHandlerSection _requestSettings;
+ private readonly IRequestHandlerSettings _requestSettings;
private readonly ILogger _logger;
private readonly IGlobalSettings _globalSettings;
private readonly ISiteDomainHelper _siteDomainHelper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly UriUtility _uriUtility;
- public DefaultUrlProvider(IRequestHandlerSection requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility)
+ public DefaultUrlProvider(IRequestHandlerSettings requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility)
{
_requestSettings = requestSettings;
_logger = logger;
diff --git a/src/Umbraco.Core/Routing/PublishedRequest.cs b/src/Umbraco.Core/Routing/PublishedRequest.cs
index 9b00e59deb..6e4d0008a9 100644
--- a/src/Umbraco.Core/Routing/PublishedRequest.cs
+++ b/src/Umbraco.Core/Routing/PublishedRequest.cs
@@ -16,7 +16,7 @@ namespace Umbraco.Web.Routing
public class PublishedRequest : IPublishedRequest
{
private readonly IPublishedRouter _publishedRouter;
- private readonly IUmbracoSettingsSection _umbracoSettingsSection;
+ private readonly IWebRoutingSettings _webRoutingSettings;
private bool _readonly; // after prepared
private bool _readonlyUri; // after preparing
@@ -33,11 +33,11 @@ namespace Umbraco.Web.Routing
/// The published router.
/// The Umbraco context.
/// The request Uri.
- internal PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IUmbracoSettingsSection umbracoSettingsSection, Uri uri = null)
+ internal PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IWebRoutingSettings webRoutingSettings, Uri uri = null)
{
UmbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
_publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter));
- _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
+ _webRoutingSettings = webRoutingSettings;
Uri = uri ?? umbracoContext.CleanedUmbracoUrl;
}
@@ -178,7 +178,7 @@ namespace Umbraco.Web.Routing
IsInternalRedirectPublishedContent = isInternalRedirect;
// must restore the template if it's an internal redirect & the config option is set
- if (isInternalRedirect && _umbracoSettingsSection.WebRouting.InternalRedirectPreservesTemplate)
+ if (isInternalRedirect && _webRoutingSettings.InternalRedirectPreservesTemplate)
{
// restore
TemplateModel = template;
diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs
similarity index 86%
rename from src/Umbraco.Web/Routing/PublishedRouter.cs
rename to src/Umbraco.Core/Routing/PublishedRouter.cs
index 1a6048e4ec..1a422dea92 100644
--- a/src/Umbraco.Web/Routing/PublishedRouter.cs
+++ b/src/Umbraco.Core/Routing/PublishedRouter.cs
@@ -4,13 +4,11 @@ using System.Threading;
using System.Globalization;
using System.IO;
using Umbraco.Core;
-using Umbraco.Web.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
-using Umbraco.Web.Macros;
using Umbraco.Web.Security;
namespace Umbraco.Web.Routing
@@ -20,47 +18,56 @@ namespace Umbraco.Web.Routing
///
public class PublishedRouter : IPublishedRouter
{
- private readonly IWebRoutingSection _webRoutingSection;
+ private readonly IWebRoutingSettings _webRoutingSettings;
private readonly ContentFinderCollection _contentFinders;
private readonly IContentLastChanceFinder _contentLastChanceFinder;
- private readonly ServiceContext _services;
private readonly IProfilingLogger _profilingLogger;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly ILogger _logger;
- private readonly IUmbracoSettingsSection _umbracoSettingsSection;
- private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IPublishedUrlProvider _publishedUrlProvider;
+ private readonly IRequestAccessor _requestAccessor;
+ private readonly IPublishedValueFallback _publishedValueFallback;
+ private readonly IPublicAccessChecker _publicAccessChecker;
+ private readonly IFileService _fileService;
+ private readonly IContentTypeService _contentTypeService;
+ private readonly IPublicAccessService _publicAccessService;
///
/// Initializes a new instance of the class.
///
public PublishedRouter(
- IWebRoutingSection webRoutingSection,
+ IWebRoutingSettings webRoutingSettings,
ContentFinderCollection contentFinders,
IContentLastChanceFinder contentLastChanceFinder,
IVariationContextAccessor variationContextAccessor,
- ServiceContext services,
IProfilingLogger proflog,
- IUmbracoSettingsSection umbracoSettingsSection,
- IHttpContextAccessor httpContextAccessor,
- IPublishedUrlProvider publishedUrlProvider)
+ IPublishedUrlProvider publishedUrlProvider,
+ IRequestAccessor requestAccessor,
+ IPublishedValueFallback publishedValueFallback,
+ IPublicAccessChecker publicAccessChecker,
+ IFileService fileService,
+ IContentTypeService contentTypeService,
+ IPublicAccessService publicAccessService)
{
- _webRoutingSection = webRoutingSection ?? throw new ArgumentNullException(nameof(webRoutingSection));
+ _webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings));
_contentFinders = contentFinders ?? throw new ArgumentNullException(nameof(contentFinders));
_contentLastChanceFinder = contentLastChanceFinder ?? throw new ArgumentNullException(nameof(contentLastChanceFinder));
- _services = services ?? throw new ArgumentNullException(nameof(services));
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_logger = proflog;
- _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
- _httpContextAccessor = httpContextAccessor;
_publishedUrlProvider = publishedUrlProvider;
+ _requestAccessor = requestAccessor;
+ _publishedValueFallback = publishedValueFallback;
+ _publicAccessChecker = publicAccessChecker;
+ _fileService = fileService;
+ _contentTypeService = contentTypeService;
+ _publicAccessService = publicAccessService;
}
///
public IPublishedRequest CreateRequest(IUmbracoContext umbracoContext, Uri uri = null)
{
- return new PublishedRequest(this, umbracoContext, _umbracoSettingsSection, uri ?? umbracoContext.CleanedUmbracoUrl);
+ return new PublishedRequest(this, umbracoContext, _webRoutingSettings, uri ?? umbracoContext.CleanedUmbracoUrl);
}
#region Request
@@ -358,7 +365,7 @@ namespace Umbraco.Web.Routing
///
public ITemplate GetTemplate(string alias)
{
- return _services.FileService.GetTemplate(alias);
+ return _fileService.GetTemplate(alias);
}
///
@@ -498,7 +505,7 @@ namespace Umbraco.Web.Routing
var redirect = false;
var valid = false;
IPublishedContent internalRedirectNode = null;
- var internalRedirectId = request.PublishedContent.Value(Constants.Conventions.Content.InternalRedirectId, defaultValue: -1);
+ var internalRedirectId = request.PublishedContent.Value(_publishedValueFallback, Constants.Conventions.Content.InternalRedirectId, defaultValue: -1);
if (internalRedirectId > 0)
{
@@ -508,7 +515,7 @@ namespace Umbraco.Web.Routing
}
else
{
- var udiInternalRedirectId = request.PublishedContent.Value(Constants.Conventions.Content.InternalRedirectId);
+ var udiInternalRedirectId = request.PublishedContent.Value(_publishedValueFallback, Constants.Conventions.Content.InternalRedirectId);
if (udiInternalRedirectId != null)
{
// try and get the redirect node from a UDI Guid
@@ -555,58 +562,34 @@ namespace Umbraco.Web.Routing
var path = request.PublishedContent.Path;
- var publicAccessAttempt = _services.PublicAccessService.IsProtected(path);
+ var publicAccessAttempt = _publicAccessService.IsProtected(path);
if (publicAccessAttempt)
{
_logger.Debug("EnsurePublishedContentAccess: Page is protected, check for access");
- var membershipHelper = Current.Factory.GetInstance();
-
- if (membershipHelper.IsLoggedIn() == false)
+ var status = _publicAccessChecker.HasMemberAccessToContent(request.PublishedContent.Id);
+ switch (status)
{
- _logger.Debug("EnsurePublishedContentAccess: Not logged in, redirect to login page");
-
- var loginPageId = publicAccessAttempt.Result.LoginNodeId;
-
- if (loginPageId != request.PublishedContent.Id)
- request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(loginPageId);
- }
- else if (_services.PublicAccessService.HasAccess(request.PublishedContent.Id, _services.ContentService, membershipHelper.CurrentUserName, membershipHelper.GetCurrentUserRoles()) == false)
- {
- _logger.Debug("EnsurePublishedContentAccess: Current member has not access, redirect to error page");
- var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
- if (errorPageId != request.PublishedContent.Id)
- request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
- }
- else
- {
- // grab the current member
- var member = membershipHelper.GetCurrentMember();
- // if the member has the "approved" and/or "locked out" properties, make sure they're correctly set before allowing access
- var memberIsActive = true;
- if (member != null)
- {
- if (member.HasProperty(Constants.Conventions.Member.IsApproved) == false)
- memberIsActive = member.Value(Constants.Conventions.Member.IsApproved);
-
- if (member.HasProperty(Constants.Conventions.Member.IsLockedOut) == false)
- memberIsActive = member.Value(Constants.Conventions.Member.IsLockedOut) == false;
- }
-
- if (memberIsActive == false)
- {
- _logger.Debug(
- "Current member is either unapproved or locked out, redirect to error page");
- var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
- if (errorPageId != request.PublishedContent.Id)
- request.PublishedContent =
- request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
- }
- else
- {
+ case PublicAccessStatus.NotLoggedIn:
+ _logger.Debug("EnsurePublishedContentAccess: Not logged in, redirect to login page");
+ SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.LoginNodeId);
+ break;
+ case PublicAccessStatus.AccessDenied:
+ _logger.Debug("EnsurePublishedContentAccess: Current member has not access, redirect to error page");
+ SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId);
+ break;
+ case PublicAccessStatus.LockedOut:
+ _logger.Debug("Current member is locked out, redirect to error page");
+ SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId);
+ break;
+ case PublicAccessStatus.NotApproved:
+ _logger.Debug("Current member is unapproved, redirect to error page");
+ SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId);
+ break;
+ case PublicAccessStatus.AccessAccepted:
_logger.Debug("Current member has access");
- }
+ break;
}
}
else
@@ -615,6 +598,12 @@ namespace Umbraco.Web.Routing
}
}
+ private static void SetPublishedContentAsOtherPage(IPublishedRequest request, int errorPageId)
+ {
+ if (errorPageId != request.PublishedContent.Id)
+ request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
+ }
+
///
/// Finds a template for the current node, if any.
///
@@ -635,9 +624,9 @@ namespace Umbraco.Web.Routing
// does not apply
// + optionally, apply the alternate template on internal redirects
var useAltTemplate = request.IsInitialPublishedContent
- || (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent);
+ || (_webRoutingSettings.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent);
var altTemplate = useAltTemplate
- ? _httpContextAccessor.GetRequiredHttpContext().Request[Constants.Conventions.Url.AltTemplate]
+ ? _requestAccessor.GetRequestValue(Constants.Conventions.Url.AltTemplate)
: null;
if (string.IsNullOrWhiteSpace(altTemplate))
@@ -674,10 +663,15 @@ namespace Umbraco.Web.Routing
_logger.Debug("FindTemplate: Look for alternative template alias={AltTemplate}", altTemplate);
// IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings
- if (request.PublishedContent.IsAllowedTemplate(altTemplate))
+ if (request.PublishedContent.IsAllowedTemplate(
+ _fileService,
+ _contentTypeService,
+ _webRoutingSettings.DisableAlternativeTemplates,
+ _webRoutingSettings.ValidateAlternativeTemplates,
+ altTemplate))
{
// allowed, use
- var template = _services.FileService.GetTemplate(altTemplate);
+ var template = _fileService.GetTemplate(altTemplate);
if (template != null)
{
@@ -731,7 +725,7 @@ namespace Umbraco.Web.Routing
if (templateId == null)
throw new InvalidOperationException("The template is not set, the page cannot render.");
- var template = _services.FileService.GetTemplate(templateId.Value);
+ var template = _fileService.GetTemplate(templateId.Value);
if (template == null)
throw new InvalidOperationException("The template with Id " + templateId + " does not exist, the page cannot render.");
_logger.Debug("GetTemplateModel: Got template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias);
@@ -750,7 +744,7 @@ namespace Umbraco.Web.Routing
if (request.PublishedContent.HasProperty(Constants.Conventions.Content.Redirect) == false)
return;
- var redirectId = request.PublishedContent.Value(Constants.Conventions.Content.Redirect, defaultValue: -1);
+ var redirectId = request.PublishedContent.Value(_publishedValueFallback, Constants.Conventions.Content.Redirect, defaultValue: -1);
var redirectUrl = "#";
if (redirectId > 0)
{
@@ -759,7 +753,7 @@ namespace Umbraco.Web.Routing
else
{
// might be a UDI instead of an int Id
- var redirectUdi = request.PublishedContent.Value(Constants.Conventions.Content.Redirect);
+ var redirectUdi = request.PublishedContent.Value