Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/AB5490-abstract-clientdependency

# Resolved Conflicts:
#	src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml
#	src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml
#	src/Umbraco.Web/Composing/Current.cs
#	src/Umbraco.Web/Editors/BackOfficeController.cs
#	src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
#	src/Umbraco.Web/Editors/PreviewController.cs
#	src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs
This commit is contained in:
Elitsa Marinovska
2020-03-17 11:01:32 +01:00
266 changed files with 2540 additions and 2008 deletions
+23 -9
View File
@@ -1,8 +1,10 @@
using System.Configuration;
using Umbraco.Configuration;
using Umbraco.Configuration.Implementations;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
@@ -18,25 +20,27 @@ namespace Umbraco.Core.Configuration
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 IUmbracoSettingsSection UmbracoSettings { get; }
public Configs Create(IIOHelper ioHelper)
public Configs Create(IIOHelper ioHelper, ILogger logger)
{
var configs = new Configs(section => ConfigurationManager.GetSection(section));
configs.Add<IGlobalSettings>(() => new GlobalSettings(ioHelper));
configs.Add(() => HostingSettings);
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
// 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(() => MachineKeyConfig);
configs.Add<IConnectionStrings>(() => new ConnectionStrings(ioHelper));
configs.Add<IConnectionStrings>(() => new ConnectionStrings(ioHelper, logger));
configs.Add<IModelsBuilderConfig>(() => new ModelsBuilderConfig(ioHelper));
@@ -47,6 +51,16 @@ namespace Umbraco.Core.Configuration
configs.Add<IActiveDirectorySettings>(() => ActiveDirectorySettings);
configs.Add<IExceptionFilterSettings>(() => ExceptionFilterSettings);
configs.Add<ITourSettings>(() => TourSettings);
configs.Add<ILoggingSettings>(() => LoggingSettings);
configs.Add<IKeepAliveSettings>(() => KeepAliveSettings);
configs.Add<IWebRoutingSettings>(() => WebRoutingSettings);
configs.Add<IRequestHandlerSettings>(() => RequestHandlerSettings);
configs.Add<ISecuritySettings>(() => SecuritySettings);
configs.Add<IUserPasswordConfiguration>(() => UserPasswordConfigurationSettings);
configs.Add<IMemberPasswordConfiguration>(() => MemberPasswordConfigurationSettings);
configs.Add<IContentSettings>(() => ContentSettings);
configs.AddCoreConfigs(ioHelper);
return configs;
}
+77 -1
View File
@@ -1,18 +1,22 @@
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
public class ConnectionStrings : IConnectionStrings
{
private readonly IIOHelper _ioHelper;
private readonly ILogger _logger;
public ConnectionStrings(IIOHelper ioHelper)
public ConnectionStrings(IIOHelper ioHelper, ILogger logger)
{
_ioHelper = ioHelper;
_logger = logger;
}
public ConfigConnectionString this[string key]
@@ -41,5 +45,77 @@ namespace Umbraco.Core.Configuration
}
var settings = ConfigurationManager.ConnectionStrings[key];
}
/// <summary>
/// Saves the connection string as a proper .net connection string in web.config.
/// </summary>
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
/// <param name="connectionString">The connection string.</param>
/// <param name="providerName">The provider name.</param>
public void SaveConnectionString(string connectionString, string providerName)
{
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(_ioHelper.Root +"/" + 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(_ioHelper.Root + "/" + 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<ConnectionStrings>("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
_logger.Info<ConnectionStrings>("Saved connection string to {ConfigFile}.", fileSource);
}
private static void AddOrUpdateAttribute(XElement element, string name, string value)
{
var attribute = element.Attribute(name);
if (attribute == null)
element.Add(new XAttribute(name, value));
else
attribute.Value = value;
}
}
}
@@ -0,0 +1,22 @@
using System.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal abstract class ConfigurationManagerConfigBase
{
private UmbracoSettingsSection _umbracoSettingsSection;
public UmbracoSettingsSection UmbracoSettingsSection
{
get
{
if (_umbracoSettingsSection is null)
{
_umbracoSettingsSection = ConfigurationManager.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection;
}
return _umbracoSettingsSection;
}
}
}
}
@@ -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<string> ImageFileTypes => UmbracoSettingsSection.Content.Imaging.ImageFileTypes;
public IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties => UmbracoSettingsSection.Content.Imaging.ImageAutoFillProperties;
public bool ResolveUrlsFromTextString => UmbracoSettingsSection.Content.ResolveUrlsFromTextString;
public IEnumerable<IContentErrorPage> Error404Collection => UmbracoSettingsSection.Content.Error404Collection;
public string PreviewBadge => UmbracoSettingsSection.Content.PreviewBadge;
public MacroErrorBehaviour MacroErrorBehaviour => UmbracoSettingsSection.Content.MacroErrors;
public IEnumerable<string> DisallowedUploadFiles => UmbracoSettingsSection.Content.DisallowedUploadFiles;
public IEnumerable<string> AllowedUploadFiles => UmbracoSettingsSection.Content.AllowedUploadFiles;
public bool ShowDeprecatedPropertyEditors => UmbracoSettingsSection.Content.ShowDeprecatedPropertyEditors;
public string LoginBackgroundImage => UmbracoSettingsSection.Content.LoginBackgroundImage;
}
}
@@ -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;
}
}
@@ -0,0 +1,9 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class LoggingSettings : ConfigurationManagerConfigBase, ILoggingSettings
{
public int MaxLogAge => UmbracoSettingsSection.Logging.MaxLogAge;
}
}
@@ -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;
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class RequestHandlerSettings : ConfigurationManagerConfigBase, IRequestHandlerSettings
{
public bool AddTrailingSlash => UmbracoSettingsSection.RequestHandler.AddTrailingSlash;
public bool ConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
public bool TryConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
public IEnumerable<IChar> CharCollection => UmbracoSettingsSection.RequestHandler.UrlReplacing.CharCollection;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -0,0 +1,16 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class WebRoutingSettings : ConfigurationManagerConfigBase, IWebRoutingSettings
{
public bool TrySkipIisCustomErrors => UmbracoSettingsSection.WebRouting.TrySkipIisCustomErrors;
public bool InternalRedirectPreservesTemplate => UmbracoSettingsSection.WebRouting.InternalRedirectPreservesTemplate;
public bool DisableAlternativeTemplates => UmbracoSettingsSection.WebRouting.DisableAlternativeTemplates;
public bool ValidateAlternativeTemplates => UmbracoSettingsSection.WebRouting.ValidateAlternativeTemplates;
public bool DisableFindContentByIdPath => UmbracoSettingsSection.WebRouting.DisableFindContentByIdPath;
public bool DisableRedirectUrlTracking => UmbracoSettingsSection.WebRouting.DisableRedirectUrlTracking;
public string UrlProviderMode => UmbracoSettingsSection.WebRouting.UrlProviderMode;
public string UmbracoApplicationUrl => UmbracoSettingsSection.WebRouting.UmbracoApplicationUrl;
}
}
@@ -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
@@ -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;
}
}
@@ -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 = @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
@@ -40,26 +40,26 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("loginBackgroundImage")]
internal InnerTextConfigurationElement<string> 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<string> IContentSection.ImageFileTypes => Imaging.ImageFileTypes;
IEnumerable<string> IContentSettings.ImageFileTypes => Imaging.ImageFileTypes;
IEnumerable<IImagingAutoFillUploadField> IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
IEnumerable<IImagingAutoFillUploadField> 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<string> IContentSection.DisallowedUploadFiles => DisallowedUploadFiles;
IEnumerable<string> IContentSettings.DisallowedUploadFiles => DisallowedUploadFiles;
IEnumerable<string> IContentSection.AllowedUploadFiles => AllowedUploadFiles;
IEnumerable<string> IContentSettings.AllowedUploadFiles => AllowedUploadFiles;
bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
bool IContentSettings.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
string IContentSettings.LoginBackgroundImage => LoginBackgroundImage;
}
}
@@ -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"];
@@ -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<int> MaxLogAge => GetOptionalTextElement("maxLogAge", -1);
int ILoggingSection.MaxLogAge => MaxLogAge;
int ILoggingSettings.MaxLogAge => MaxLogAge;
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfigurationSection
internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfiguration
{
}
}
@@ -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<bool> 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<IChar> IRequestHandlerSection.CharCollection => UrlReplacing.CharCollection;
IEnumerable<IChar> IRequestHandlerSettings.CharCollection => UrlReplacing.CharCollection;
}
}
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class SecurityElement : UmbracoConfigurationElement, ISecuritySection
internal class SecurityElement : UmbracoConfigurationElement, ISecuritySettings
{
[ConfigurationProperty("keepUserLoggedIn")]
internal InnerTextConfigurationElement<bool> 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;
/// <summary>
/// Used to enable/disable the forgot password functionality on the back office login screen
/// </summary>
bool ISecuritySection.AllowPasswordReset => AllowPasswordReset;
bool ISecuritySettings.AllowPasswordReset => AllowPasswordReset;
/// <summary>
/// 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.
/// </remarks>
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;
}
}
@@ -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 ?
@@ -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;
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfigurationSection
internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfiguration
{
}
}
@@ -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"];
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Returns a list of scannable assemblies based on an entry point assembly and it's references
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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",
};
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<Assembly> Assemblies
{
get
{
var finder = new FindAssembliesWithReferencesTo(new[] { _entryPointAssembly }, UmbracoCoreAssemblyNames, true);
return finder.Find();
}
}
}
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Finds Assemblies from the entry point assemblies, it's dependencies and it's transitive dependencies that reference that targetAssemblyNames
/// </summary>
/// <remarkes>
/// borrowed and modified from here https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/FindAssembliesWithReferencesTo.cs
/// </remarkes>
internal class FindAssembliesWithReferencesTo
{
private readonly Assembly[] _referenceAssemblies;
private readonly string[] _targetAssemblies;
private readonly bool _includeTargets;
/// <summary>
/// Constructor
/// </summary>
/// <param name="referenceAssemblies">Entry point assemblies</param>
/// <param name="targetAssemblyNames">Used to check if the entry point or it's transitive assemblies reference these assembly names</param>
/// <param name="includeTargets">If true will also use the target assembly names as entry point assemblies</param>
public FindAssembliesWithReferencesTo(Assembly[] referenceAssemblies, string[] targetAssemblyNames, bool includeTargets)
{
_referenceAssemblies = referenceAssemblies;
_targetAssemblies = targetAssemblyNames;
_includeTargets = includeTargets;
}
public IEnumerable<Assembly> Find()
{
var referenceItems = new List<Assembly>();
foreach (var assembly in _referenceAssemblies)
{
referenceItems.Add(assembly);
}
if (_includeTargets)
{
foreach(var target in _targetAssemblies)
{
referenceItems.Add(Assembly.Load(target));
}
}
var provider = new ReferenceResolver(_targetAssemblies, referenceItems);
var assemblyNames = provider.ResolveAssemblies();
return assemblyNames.ToList();
}
}
}
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Reflection;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides a list of assemblies that can be scanned
/// </summary>
public interface IAssemblyProvider
{
IEnumerable<Assembly> Assemblies { get; }
}
}
@@ -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
{
/// <summary>
/// Resolves assemblies that reference one of the specified "targetAssemblies" either directly or transitively.
/// </summary>
/// <remarks>
/// Borrowed and modified from https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/ReferenceResolver.cs
/// </remarks>
internal class ReferenceResolver
{
private readonly HashSet<string> _umbracoAssemblies;
private readonly IReadOnlyList<Assembly> _assemblies;
private readonly Dictionary<Assembly, Classification> _classifications;
private readonly List<Assembly> _lookup = new List<Assembly>();
public ReferenceResolver(IReadOnlyList<string> targetAssemblies, IReadOnlyList<Assembly> entryPointAssemblies)
{
_umbracoAssemblies = new HashSet<string>(targetAssemblies, StringComparer.Ordinal);
_assemblies = entryPointAssemblies;
_classifications = new Dictionary<Assembly, Classification>();
foreach (var item in entryPointAssemblies)
{
_lookup.Add(item);
}
}
/// <summary>
/// Returns a list of assemblies that directly reference or transitively reference the targetAssemblies
/// </summary>
/// <returns></returns>
/// <remarks>
/// This includes all assemblies in the same location as the entry point assemblies
/// </remarks>
public IEnumerable<Assembly> ResolveAssemblies()
{
var applicationParts = new List<Assembly>();
var assemblies = new HashSet<Assembly>(_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<string> GetAssemblyFolders(IEnumerable<Assembly> 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<Assembly> 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,
}
}
}
+57 -110
View File
@@ -1,106 +1,35 @@
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
{
/// <inheritdoc cref="ITypeFinder"/>
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<string>();
_allAssemblies = new Lazy<HashSet<Assembly>>(() =>
{
HashSet<Assembly> 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<Assembly>();
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<HashSet<Assembly>> _allAssemblies;
private readonly IAssemblyProvider _assemblyProvider;
private volatile HashSet<Assembly> _localFilteredAssemblyCache;
private readonly object _localFilteredAssemblyCacheLocker = new object();
private readonly List<string> _notifiedLoadExceptionAssemblies = new List<string>();
private static readonly ConcurrentDictionary<string, Type> TypeNamesCache= new ConcurrentDictionary<string, Type>();
private string _rootDir = "";
private static readonly ConcurrentDictionary<string, Type> TypeNamesCache = new ConcurrentDictionary<string, Type>();
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, 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;
_assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty<string>();
}
private bool AcceptsLoadExceptions(Assembly a)
@@ -119,22 +48,8 @@ namespace Umbraco.Core.Composing
});
}
/// <summary>
/// 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
/// </summary>
/// <remarks>
/// 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
/// </remarks>
private IEnumerable<Assembly> GetAllAssemblies()
{
return _allAssemblies.Value;
}
private IEnumerable<Assembly> GetAllAssemblies() => _assemblyProvider.Assemblies;
/// <inheritdoc />
public IEnumerable<Assembly> AssembliesToScan
@@ -181,7 +96,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"
/// </remarks>
private static readonly string[] KnownAssemblyExclusionFilter = {
internal static readonly string[] KnownAssemblyExclusionFilter = {
"mscorlib,",
"netstandard,",
"System,",
"Antlr3.",
"AutoMapper,",
"AutoMapper.",
@@ -228,7 +146,14 @@ namespace Umbraco.Core.Composing
"WebDriver,",
"itextsharp,",
"mscorlib,",
"nunit.framework,",
"NUnit,",
"NUnit.",
"NUnit3.",
"Selenium.",
"ImageProcessor",
"MiniProfiler.",
"Owin,",
"SQLite",
};
/// <summary>
@@ -290,6 +215,11 @@ namespace Umbraco.Core.Composing
/// <returns></returns>
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 +270,24 @@ namespace Umbraco.Core.Composing
var stack = new Stack<Assembly>();
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<Type> 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 +307,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 +344,25 @@ namespace Umbraco.Core.Composing
var stack = new Stack<Assembly>();
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<Type> 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 +382,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 +470,5 @@ namespace Umbraco.Core.Composing
#endregion
}
}
@@ -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
{
/// <summary>
/// TypeFinder config via appSettings
/// </summary>
internal class TypeFinderConfig : ITypeFinderConfig
{
private readonly ITypeFinderSettings _settings;
private IEnumerable<string> _assembliesAcceptingLoadExceptions;
public TypeFinderConfig(ITypeFinderSettings settings)
{
_settings = settings;
}
public IEnumerable<string> AssembliesAcceptingLoadExceptions
{
get
{
if (_assembliesAcceptingLoadExceptions != null)
return _assembliesAcceptingLoadExceptions;
var s = _settings.AssembliesAcceptingLoadExceptions;
return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
? Array.Empty<string>()
: s.Split(',').Select(x => x.Trim()).ToArray();
}
}
}
}
+3 -3
View File
@@ -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.
/// </remarks>
public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable<Assembly> assemblies)
public static IReadOnlyList<Assembly> GetReferencingAssemblies(Assembly assembly, IEnumerable<Assembly> 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();
}
/// <summary>
+22 -22
View File
@@ -516,29 +516,29 @@ namespace Umbraco.Core.Composing
#region Get Assembly Attributes
/// <summary>
/// Gets the assembly attributes of the specified type <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The attribute type.</typeparam>
/// <returns>
/// The assembly attributes of the specified type <typeparamref name="T" />.
/// </returns>
public IEnumerable<T> GetAssemblyAttributes<T>()
where T : Attribute
{
return AssembliesToScan.SelectMany(a => a.GetCustomAttributes<T>()).ToList();
}
///// <summary>
///// Gets the assembly attributes of the specified type <typeparamref name="T" />.
///// </summary>
///// <typeparam name="T">The attribute type.</typeparam>
///// <returns>
///// The assembly attributes of the specified type <typeparamref name="T" />.
///// </returns>
//public IEnumerable<T> GetAssemblyAttributes<T>()
// where T : Attribute
//{
// return AssembliesToScan.SelectMany(a => a.GetCustomAttributes<T>()).ToList();
//}
/// <summary>
/// Gets all the assembly attributes.
/// </summary>
/// <returns>
/// All assembly attributes.
/// </returns>
public IEnumerable<Attribute> GetAssemblyAttributes()
{
return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
}
///// <summary>
///// Gets all the assembly attributes.
///// </summary>
///// <returns>
///// All assembly attributes.
///// </returns>
//public IEnumerable<Attribute> GetAssemblyAttributes()
//{
// return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
//}
/// <summary>
/// Gets the assembly attributes of the specified <paramref name="attributeTypes" />.
@@ -25,8 +25,23 @@ namespace Umbraco.Core
public static IConnectionStrings ConnectionStrings(this Configs configs)
=> configs.GetConfig<IConnectionStrings>();
public static IUmbracoSettingsSection Settings(this Configs configs)
=> configs.GetConfig<IUmbracoSettingsSection>();
public static IContentSettings Content(this Configs configs)
=> configs.GetConfig<IContentSettings>();
public static ISecuritySettings Security(this Configs configs)
=> configs.GetConfig<ISecuritySettings>();
public static IUserPasswordConfiguration UserPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IUserPasswordConfiguration>();
public static IMemberPasswordConfiguration MemberPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IMemberPasswordConfiguration>();
public static IRequestHandlerSettings RequestHandler(this Configs configs)
=> configs.GetConfig<IRequestHandlerSettings>();
public static IWebRoutingSettings WebRouting(this Configs configs)
=> configs.GetConfig<IWebRoutingSettings>();
public static IHealthChecks HealthChecks(this Configs configs)
=> configs.GetConfig<IHealthChecks>();
@@ -37,24 +52,6 @@ namespace Umbraco.Core
public static ICoreDebug CoreDebug(this Configs configs)
=> configs.GetConfig<ICoreDebug>();
public static IUserPasswordConfiguration UserPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IUserPasswordConfiguration>();
public static IMemberPasswordConfiguration MemberPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IMemberPasswordConfiguration>();
public static void AddPasswordConfigurations(this Configs configs)
{
configs.Add<IUserPasswordConfiguration>(() =>
{
return new UserPasswordConfiguration(configs.Settings().Security.UserPasswordConfiguration);
});
configs.Add<IMemberPasswordConfiguration>(() =>
{
return new MemberPasswordConfiguration(configs.Settings().Security.MemberPasswordConfiguration);
});
}
public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper)
{
var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config));
@@ -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(IIOHelper ioHelper, ILogger logger);
}
}
@@ -8,5 +8,6 @@ namespace Umbraco.Core.Configuration
}
void RemoveConnectionString(string umbracoConnectionName);
void SaveConnectionString(string connectionString, string providerName);
}
}
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration
/// </summary>
public class MemberPasswordConfiguration : PasswordConfiguration, IMemberPasswordConfiguration
{
public MemberPasswordConfiguration(IMemberPasswordConfigurationSection configSection)
: base(configSection)
{
public MemberPasswordConfiguration(IMemberPasswordConfiguration configSettings)
: base(configSettings)
{
}
}
}
@@ -5,21 +5,21 @@ 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;
UseLegacyEncoding = configSettings.UseLegacyEncoding;
HashAlgorithmType = configSettings.HashAlgorithmType;
MaxFailedAccessAttemptsBeforeLockout = configSettings.MaxFailedAccessAttemptsBeforeLockout;
}
public int RequiredLength { get; }
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
/// <param name="extension">The file extension.</param>
/// <param name="contentConfig"></param>
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
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.
/// </summary>
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);
}
/// <summary>
/// Gets the auto-fill configuration for a specified property alias.
/// </summary>
/// <param name="contentSection"></param>
/// <param name="contentSettings"></param>
/// <param name="propertyTypeAlias">The property type alias.</param>
/// <returns>The auto-fill configuration for the specified property alias, or null.</returns>
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);
}
}
@@ -2,6 +2,6 @@
{
public interface IBackOfficeSection
{
ITourSection Tours { get; }
ITourSettings Tours { get; }
}
}
@@ -3,7 +3,7 @@ using Umbraco.Core.Macros;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IContentSection : IUmbracoConfigurationSection
public interface IContentSettings : IUmbracoConfigurationSection
{
string NotificationEmailAddress { get; }
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IKeepAliveSection : IUmbracoConfigurationSection
public interface IKeepAliveSettings : IUmbracoConfigurationSection
{
bool DisableKeepAliveTask { get; }
string KeepAlivePingUrl { get; }
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface ILoggingSection : IUmbracoConfigurationSection
public interface ILoggingSettings : IUmbracoConfigurationSection
{
int MaxLogAge { get; }
}
@@ -1,6 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IMemberPasswordConfigurationSection : IPasswordConfigurationSection
{
}
}
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IRequestHandlerSection : IUmbracoConfigurationSection
public interface IRequestHandlerSettings : IUmbracoConfigurationSection
{
bool AddTrailingSlash { get; }
@@ -1,9 +1,9 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface ISecuritySection : IUmbracoConfigurationSection
public interface ISecuritySettings : IUmbracoConfigurationSection
{
bool KeepUserLoggedIn { get; }
bool HideDisabledUsersInBackoffice { get; }
/// <summary>
@@ -23,9 +23,5 @@
/// When this is false, the username and email fields will be shown in the user section.
/// </remarks>
bool UsernameIsEmail { get; }
IUserPasswordConfigurationSection UserPasswordConfiguration { get; }
IMemberPasswordConfigurationSection MemberPasswordConfiguration { get; }
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface ITourSection
public interface ITourSettings
{
bool EnableTours { get; }
}
@@ -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; }
}
}
@@ -1,6 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IUserPasswordConfigurationSection : IPasswordConfigurationSection
{
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IWebRoutingSection : IUmbracoConfigurationSection
public interface IWebRoutingSettings : IUmbracoConfigurationSection
{
bool TrySkipIisCustomErrors { get; }
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration
/// </summary>
public class UserPasswordConfiguration : PasswordConfiguration, IUserPasswordConfiguration
{
public UserPasswordConfiguration(IUserPasswordConfigurationSection configSection)
: base(configSection)
{
public UserPasswordConfiguration(IUserPasswordConfiguration configSettings)
: base(configSettings)
{
}
}
}
@@ -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)
+2 -2
View File
@@ -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;
@@ -18,11 +18,11 @@ namespace Umbraco.Web.Routing
{
private readonly ILogger _logger;
private readonly IRequestAccessor _requestAccessor;
private readonly IWebRoutingSection _webRoutingSection;
private readonly IWebRoutingSettings _webRoutingSettings;
public ContentFinderByIdPath(IWebRoutingSection webRoutingSection, ILogger logger, IRequestAccessor requestAccessor)
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));
_requestAccessor = requestAccessor;
}
@@ -36,7 +36,7 @@ namespace Umbraco.Web.Routing
{
if (frequest.UmbracoContext != null && frequest.UmbracoContext.InPreviewMode == false
&& _webRoutingSection.DisableFindContentByIdPath)
&& _webRoutingSettings.DisableFindContentByIdPath)
return false;
IPublishedContent node = null;
@@ -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;
}
/// <summary>
@@ -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<ContentFinderByUrlAndTemplate>("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id);
frequest.PublishedContent = null; // clear
@@ -12,14 +12,14 @@ namespace Umbraco.Web.Routing
/// </summary>
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;
+4 -4
View File
@@ -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
/// <param name="publishedRouter">The published router.</param>
/// <param name="umbracoContext">The Umbraco context.</param>
/// <param name="uri">The request <c>Uri</c>.</param>
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;
+7 -10
View File
@@ -19,13 +19,12 @@ namespace Umbraco.Web.Routing
/// </summary>
public class PublishedRouter : IPublishedRouter
{
private readonly IWebRoutingSection _webRoutingSection;
private readonly IWebRoutingSettings _webRoutingSettings;
private readonly ContentFinderCollection _contentFinders;
private readonly IContentLastChanceFinder _contentLastChanceFinder;
private readonly IProfilingLogger _profilingLogger;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly ILogger _logger;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IPublishedUrlProvider _publishedUrlProvider;
private readonly IRequestAccessor _requestAccessor;
private readonly IPublishedValueFallback _publishedValueFallback;
@@ -38,12 +37,11 @@ namespace Umbraco.Web.Routing
/// Initializes a new instance of the <see cref="PublishedRouter"/> class.
/// </summary>
public PublishedRouter(
IWebRoutingSection webRoutingSection,
IWebRoutingSettings webRoutingSettings,
ContentFinderCollection contentFinders,
IContentLastChanceFinder contentLastChanceFinder,
IVariationContextAccessor variationContextAccessor,
IProfilingLogger proflog,
IUmbracoSettingsSection umbracoSettingsSection,
IPublishedUrlProvider publishedUrlProvider,
IRequestAccessor requestAccessor,
IPublishedValueFallback publishedValueFallback,
@@ -52,13 +50,12 @@ namespace Umbraco.Web.Routing
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));
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_logger = proflog;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_publishedUrlProvider = publishedUrlProvider;
_requestAccessor = requestAccessor;
_publishedValueFallback = publishedValueFallback;
@@ -71,7 +68,7 @@ namespace Umbraco.Web.Routing
/// <inheritdoc />
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
@@ -628,7 +625,7 @@ 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
? _requestAccessor.GetRequestValue(Constants.Conventions.Url.AltTemplate)
: null;
@@ -670,8 +667,8 @@ namespace Umbraco.Web.Routing
if (request.PublishedContent.IsAllowedTemplate(
_fileService,
_contentTypeService,
_umbracoSettingsSection.WebRouting.DisableAlternativeTemplates,
_umbracoSettingsSection.WebRouting.ValidateAlternativeTemplates,
_webRoutingSettings.DisableAlternativeTemplates,
_webRoutingSettings.ValidateAlternativeTemplates,
altTemplate))
{
// allowed, use
+1 -1
View File
@@ -61,7 +61,7 @@ namespace Umbraco.Web
// maps an internal umbraco uri to a public uri
// ie with virtual directory, .aspx if required...
public Uri UriFromUmbraco(Uri uri, IGlobalSettings globalSettings, IRequestHandlerSection requestConfig)
public Uri UriFromUmbraco(Uri uri, IGlobalSettings globalSettings, IRequestHandlerSettings requestConfig)
{
var path = uri.GetSafeAbsolutePath();
+1 -1
View File
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Routing
/// <param name="mediaUrlProviders">The list of media url providers.</param>
/// <param name="variationContextAccessor">The current variation accessor.</param>
/// <param name="propertyEditorCollection"></param>
public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IWebRoutingSection routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor)
public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IWebRoutingSettings routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor)
{
if (routingSettings == null) throw new ArgumentNullException(nameof(routingSettings));
+4 -4
View File
@@ -12,16 +12,16 @@ namespace Umbraco.Web.Scheduling
public class KeepAlive : RecurringTaskBase
{
private readonly IRuntimeState _runtime;
private readonly IKeepAliveSection _keepAliveSection;
private readonly IKeepAliveSettings _keepAliveSettings;
private readonly IProfilingLogger _logger;
private static HttpClient _httpClient;
public KeepAlive(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IRuntimeState runtime, IKeepAliveSection keepAliveSection, IProfilingLogger logger)
IRuntimeState runtime, IKeepAliveSettings keepAliveSettings, IProfilingLogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
_keepAliveSection = keepAliveSection;
_keepAliveSettings = keepAliveSettings;
_logger = logger;
if (_httpClient == null)
_httpClient = new HttpClient();
@@ -49,7 +49,7 @@ namespace Umbraco.Web.Scheduling
using (_logger.DebugDuration<KeepAlive>("Keep alive executing", "Keep alive complete"))
{
var keepAlivePingUrl = _keepAliveSection.KeepAlivePingUrl;
var keepAlivePingUrl = _keepAliveSettings.KeepAlivePingUrl;
try
{
if (keepAlivePingUrl.Contains("{umbracoApplicationUrl}"))
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Strings
{
#region Ctor, consts and vars
public DefaultShortStringHelper(IUmbracoSettingsSection settings)
public DefaultShortStringHelper(IRequestHandlerSettings settings)
{
_config = new DefaultShortStringHelperConfig().WithDefault(settings);
}
@@ -619,6 +619,6 @@ namespace Umbraco.Core.Strings
return new string(output, 0, opos);
}
#endregion
#endregion
}
}
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Strings
public string DefaultCulture { get; set; } = ""; // invariant
public Dictionary<string, string> UrlReplaceCharacters { get; set; }
public DefaultShortStringHelperConfig WithConfig(Config config)
{
return WithConfig(DefaultCulture, CleanStringType.RoleMask, config);
@@ -57,16 +57,16 @@ namespace Umbraco.Core.Strings
/// Sets the default configuration.
/// </summary>
/// <returns>The short string helper.</returns>
public DefaultShortStringHelperConfig WithDefault(IUmbracoSettingsSection umbracoSettings)
public DefaultShortStringHelperConfig WithDefault(IRequestHandlerSettings requestHandlerSettings)
{
UrlReplaceCharacters = umbracoSettings.RequestHandler.CharCollection
UrlReplaceCharacters = requestHandlerSettings.CharCollection
.Where(x => string.IsNullOrEmpty(x.Char) == false)
.ToDictionary(x => x.Char, x => x.Replacement);
var urlSegmentConvertTo = CleanStringType.Utf8;
if (umbracoSettings.RequestHandler.ConvertUrlsToAscii)
if (requestHandlerSettings.ConvertUrlsToAscii)
urlSegmentConvertTo = CleanStringType.Ascii;
if (umbracoSettings.RequestHandler.TryConvertUrlsToAscii)
if (requestHandlerSettings.TryConvertUrlsToAscii)
urlSegmentConvertTo = CleanStringType.TryAscii;
return WithConfig(CleanStringType.UrlSegment, new Config
+4 -4
View File
@@ -7,16 +7,16 @@ namespace Umbraco.Web.Templates
{
public sealed class HtmlUrlParser
{
private readonly IContentSection _contentSection;
private readonly IContentSettings _contentSettings;
private readonly IIOHelper _ioHelper;
private readonly IProfilingLogger _logger;
private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
public HtmlUrlParser(IContentSection contentSection, IProfilingLogger logger, IIOHelper ioHelper)
public HtmlUrlParser(IContentSettings contentSettings, IProfilingLogger logger, IIOHelper ioHelper)
{
_contentSection = contentSection;
_contentSettings = contentSettings;
_ioHelper = ioHelper;
_logger = logger;
}
@@ -32,7 +32,7 @@ namespace Umbraco.Web.Templates
/// </remarks>
public string EnsureUrls(string text)
{
if (_contentSection.ResolveUrlsFromTextString == false) return text;
if (_contentSettings.ResolveUrlsFromTextString == false) return text;
using (var timer = _logger.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
{
@@ -6,8 +6,6 @@ using System.Text.RegularExpressions;
using Examine;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Models.ContentEditing;
@@ -1,24 +0,0 @@
using Umbraco.Core.Configuration;
using Umbraco.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Core.Composing.CompositionExtensions
{
/// <summary>
/// Compose configurations.
/// </summary>
internal static class Configuration
{
public static Composition ComposeConfiguration(this Composition composition)
{
// common configurations are already registered
// register others
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().Content);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().RequestHandler);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().Security);
return composition;
}
}
}
@@ -18,9 +18,9 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
private readonly IRuntimeState _runtimeState;
private readonly ILogger _logger;
private readonly IGlobalSettings _globalSettings;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IContentSettings _contentSettings;
public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecks healthChecks, IUmbracoSettingsSection umbracoSettingsSection) : base(healthChecks)
public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecks healthChecks, IContentSettings contentSettings) : base(healthChecks)
{
var recipientEmail = Settings["recipientEmail"]?.Value;
if (string.IsNullOrWhiteSpace(recipientEmail))
@@ -35,7 +35,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
_runtimeState = runtimeState;
_logger = logger;
_globalSettings = globalSettings;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
}
public string RecipientEmail { get; }
@@ -74,7 +74,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
private MailMessage CreateMailMessage(string subject, string message)
{
var to = _umbracoSettingsSection.Content.NotificationEmailAddress;
var to = _contentSettings.NotificationEmailAddress;
if (string.IsNullOrWhiteSpace(subject))
subject = "Umbraco Health Check Status";
@@ -17,13 +17,13 @@ namespace Umbraco.Web.Media
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly ILogger _logger;
private readonly IContentSection _contentSection;
private readonly IContentSettings _contentSettings;
public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSection contentSection)
public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSettings contentSettings)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_contentSection = contentSection ?? throw new ArgumentNullException(nameof(contentSection));
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
}
/// <summary>
@@ -68,7 +68,7 @@ namespace Umbraco.Web.Media
using (var filestream = _mediaFileSystem.OpenFile(filepath))
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
}
}
@@ -102,7 +102,7 @@ namespace Umbraco.Web.Media
else
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
}
}
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Migrations.Install
private readonly IIOHelper _ioHelper;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator;
private readonly IConnectionStrings _connectionStrings;
private DatabaseSchemaResult _databaseSchemaValidationResult;
@@ -44,7 +45,8 @@ namespace Umbraco.Core.Migrations.Install
IKeyValueService keyValueService,
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator)
IDbProviderFactoryCreator dbProviderFactoryCreator,
IConnectionStrings connectionStrings)
{
_scopeProvider = scopeProvider;
_globalSettings = globalSettings;
@@ -56,6 +58,7 @@ namespace Umbraco.Core.Migrations.Install
_ioHelper = ioHelper;
_umbracoVersion = umbracoVersion;
_dbProviderFactoryCreator = dbProviderFactoryCreator;
_connectionStrings = connectionStrings;
}
#region Status
@@ -138,12 +141,12 @@ namespace Umbraco.Core.Migrations.Install
/// </summary>
public void ConfigureEmbeddedDatabaseConnection()
{
ConfigureEmbeddedDatabaseConnection(_databaseFactory, _ioHelper, _logger);
ConfigureEmbeddedDatabaseConnection(_databaseFactory, _ioHelper);
}
private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper, ILogger logger)
private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper)
{
SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, ioHelper, logger);
_connectionStrings.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
var path = Path.Combine(ioHelper.GetRootDirectorySafe(), "App_Data", "Umbraco.sdf");
if (File.Exists(path) == false)
@@ -166,7 +169,7 @@ namespace Umbraco.Core.Migrations.Install
{
const string providerName = Constants.DbProviderNames.SqlServer;
SaveConnectionString(connectionString, providerName, _ioHelper, _logger);
_connectionStrings.SaveConnectionString(connectionString, providerName);
_databaseFactory.Configure(connectionString, providerName);
}
@@ -182,7 +185,7 @@ namespace Umbraco.Core.Migrations.Install
{
var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName);
SaveConnectionString(connectionString, providerName, _ioHelper, _logger);
_connectionStrings.SaveConnectionString(connectionString, providerName);
_databaseFactory.Configure(connectionString, providerName);
}
@@ -213,7 +216,7 @@ namespace Umbraco.Core.Migrations.Install
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
{
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer, _ioHelper, _logger);
_connectionStrings.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer);
_databaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer);
}
@@ -282,75 +285,8 @@ namespace Umbraco.Core.Migrations.Install
return server.ToLower().StartsWith("tcp:".ToLower());
}
/// <summary>
/// Saves the connection string as a proper .net connection string in web.config.
/// </summary>
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
/// <param name="connectionString">The connection string.</param>
/// <param name="providerName">The provider name.</param>
/// <param name="logger">A logger.</param>
private static void SaveConnectionString(string connectionString, string providerName, IIOHelper ioHelper, ILogger logger)
{
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(ioHelper.Root +"/" + 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(ioHelper.Root + "/" + 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<DatabaseBuilder>("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
logger.Info<DatabaseBuilder>("Saved connection string to {ConfigFile}.", fileSource);
}
private static void AddOrUpdateAttribute(XElement element, string name, string value)
{
var attribute = element.Attribute(name);
if (attribute == null)
element.Add(new XAttribute(name, value));
else
attribute.Value = value;
}
#endregion
@@ -33,7 +33,7 @@ namespace Umbraco.Web.Models.ContentEditing
if (UserGroups.Any() == false)
yield return new ValidationResult("A user must be assigned to at least one group", new[] { nameof(UserGroups) });
if (Current.Configs.Settings().Security.UsernameIsEmail == false && Username.IsNullOrWhiteSpace())
if (Current.Configs.Security().UsernameIsEmail == false && Username.IsNullOrWhiteSpace())
yield return new ValidationResult("A username cannot be empty", new[] { nameof(Username) });
}
}
@@ -15,13 +15,13 @@ namespace Umbraco.Web.Models.Mapping
{
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IContentSettings _contentSettings;
public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IUmbracoSettingsSection umbracoSettingsSection)
public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IContentSettings contentSettings)
{
_propertyEditors = propertyEditors;
_logger = logger;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
}
private static readonly int[] SystemIds =
@@ -128,9 +128,8 @@ namespace Umbraco.Web.Models.Mapping
private IEnumerable<PropertyEditorBasic> MapAvailableEditors(IDataType source, MapperContext context)
{
var contentSection = _umbracoSettingsSection.Content;
var properties = _propertyEditors
.Where(x => !x.IsDeprecated || contentSection.ShowDeprecatedPropertyEditors || source.EditorAlias == x.Alias)
.Where(x => !x.IsDeprecated || _contentSettings.ShowDeprecatedPropertyEditors || source.EditorAlias == x.Alias)
.OrderBy(x => x.Name);
return context.MapEnumerable<IDataEditor, PropertyEditorBasic>(properties);
}
@@ -175,6 +175,12 @@ namespace Umbraco.Web.Models.Mapping
target.Name = source.Values.ContainsKey(UmbracoExamineFieldNames.NodeNameFieldName) ? source.Values[UmbracoExamineFieldNames.NodeNameFieldName] : "[no name]";
var culture = context.GetCulture();
if(culture.IsNullOrWhiteSpace() == false)
{
target.Name = source.Values.ContainsKey($"nodeName_{culture}") ? source.Values[$"nodeName_{culture}"] : target.Name;
}
if (source.Values.TryGetValue(UmbracoExamineFieldNames.UmbracoFileFieldName, out var umbracoFile))
{
if (umbracoFile != null)
@@ -27,9 +27,9 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets the urls of a media item.
/// </summary>
public static string[] GetUrls(this IMedia media, IContentSection contentSection, MediaUrlGeneratorCollection mediaUrlGenerators)
public static string[] GetUrls(this IMedia media, IContentSettings contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators)
{
return contentSection.ImageAutoFillProperties
return contentSettings.ImageAutoFillProperties
.Select(field => media.GetUrl(field.Alias, mediaUrlGenerators))
.Where(link => string.IsNullOrWhiteSpace(link) == false)
.ToArray();
@@ -168,6 +168,7 @@ namespace Umbraco.Core.Models
/// <inheritdoc />
[DataMember]
[DoNotClone]
public Lazy<int> PropertyGroupId
{
get => _propertyGroupId;
@@ -653,10 +653,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var entity = new MediaEntitySlim();
BuildContentEntity(entity, dto);
if (dto is MediaEntityDto contentDto)
// fill in the media info
if (dto is MediaEntityDto mediaEntityDto)
{
// fill in the media info
entity.MediaPath = contentDto.MediaPath;
entity.MediaPath = mediaEntityDto.MediaPath;
}
else if (dto is GenericContentEntityDto genericContentEntityDto)
{
entity.MediaPath = genericContentEntityDto.MediaPath;
}
return entity;
@@ -119,7 +119,7 @@ namespace Umbraco.Core.PropertyEditors
/// <para>Technically, it could be cached by datatype but let's keep things
/// simple enough for now.</para>
/// </remarks>
public IDataValueEditor GetValueEditor(object configuration)
public virtual IDataValueEditor GetValueEditor(object configuration)
{
// if an explicit value editor has been set (by the manifest parser)
// then return it, and ignore the configuration, which is going to be
@@ -22,23 +22,21 @@ namespace Umbraco.Web.PropertyEditors
public class FileUploadPropertyEditor : DataEditor, IMediaUrlGenerator
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSection _contentSection;
private readonly IContentSettings _contentSettings;
private readonly UploadAutoFillProperties _uploadAutoFillProperties;
private readonly IDataTypeService _dataTypeService;
private readonly ILocalizationService _localizationService;
private readonly ILocalizedTextService _localizedTextService;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
public FileUploadPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSection contentSection, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection)
public FileUploadPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper)
: base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_contentSection = contentSection;
_contentSettings = contentSettings;
_dataTypeService = dataTypeService;
_localizationService = localizationService;
_localizedTextService = localizedTextService;
_uploadAutoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSection);
_umbracoSettingsSection = umbracoSettingsSection;
_uploadAutoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSettings);
}
/// <summary>
@@ -47,8 +45,8 @@ namespace Umbraco.Web.PropertyEditors
/// <returns>The corresponding property value editor.</returns>
protected override IDataValueEditor CreateValueEditor()
{
var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, _umbracoSettingsSection);
editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, _umbracoSettingsSection));
var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, _contentSettings);
editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, _contentSettings));
return editor;
}
@@ -179,7 +177,7 @@ namespace Umbraco.Web.PropertyEditors
foreach (var property in properties)
{
var autoFillConfig = _contentSection.GetConfig(property.Alias);
var autoFillConfig = _contentSettings.GetConfig(property.Alias);
if (autoFillConfig == null) continue;
foreach (var pvalue in property.Values)
@@ -16,13 +16,13 @@ namespace Umbraco.Web.PropertyEditors
internal class FileUploadPropertyValueEditor : DataValueEditor
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IContentSettings _contentSettings;
public FileUploadPropertyValueEditor(DataEditorAttribute attribute, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection)
public FileUploadPropertyValueEditor(DataEditorAttribute attribute, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings)
: base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
}
/// <summary>
@@ -101,7 +101,7 @@ namespace Umbraco.Web.PropertyEditors
{
// process the file
// no file, invalid file, reject change
if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _umbracoSettingsSection) == false)
if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false)
return null;
// get the filepath
@@ -29,17 +29,16 @@ namespace Umbraco.Web.PropertyEditors
public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSection _contentSettings;
private readonly IContentSettings _contentSettings;
private readonly IDataTypeService _dataTypeService;
private readonly ILocalizationService _localizationService;
private readonly IIOHelper _ioHelper;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly UploadAutoFillProperties _autoFillProperties;
/// <summary>
/// Initializes a new instance of the <see cref="ImageCropperPropertyEditor"/> class.
/// </summary>
public ImageCropperPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSection contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService, IUmbracoSettingsSection umbracoSettingsSection)
public ImageCropperPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService)
: base(logger, dataTypeService, localizationService, localizedTextService,shortStringHelper)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
@@ -47,7 +46,6 @@ namespace Umbraco.Web.PropertyEditors
_dataTypeService = dataTypeService;
_localizationService = localizationService;
_ioHelper = ioHelper;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
// TODO: inject?
_autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, _contentSettings);
@@ -68,7 +66,7 @@ namespace Umbraco.Web.PropertyEditors
/// Creates the corresponding property value editor.
/// </summary>
/// <returns>The corresponding property value editor.</returns>
protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, Logger, _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _umbracoSettingsSection);
protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, Logger, _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings);
/// <summary>
/// Creates the corresponding preValue editor.
@@ -22,14 +22,14 @@ namespace Umbraco.Web.PropertyEditors
{
private readonly ILogger _logger;
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IContentSettings _contentSettings;
public ImageCropperPropertyValueEditor(DataEditorAttribute attribute, ILogger logger, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection)
public ImageCropperPropertyValueEditor(DataEditorAttribute attribute, ILogger logger, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings)
: base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
}
/// <summary>
@@ -146,7 +146,7 @@ namespace Umbraco.Web.PropertyEditors
{
// process the file
// no file, invalid file, reject change
if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _umbracoSettingsSection) == false)
if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false)
return null;
// get the filepath
@@ -16,12 +16,12 @@ namespace Umbraco.Web.PropertyEditors
internal class UploadFileTypeValidator : IValueValidator
{
private readonly ILocalizedTextService _localizedTextService;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IContentSettings _contentSettings;
public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IUmbracoSettingsSection umbracoSettingsSection)
public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IContentSettings contentSettings)
{
_localizedTextService = localizedTextService;
_umbracoSettingsSection = umbracoSettingsSection;
_contentSettings = contentSettings;
}
public IEnumerable<ValidationResult> Validate(object value, string valueType, object dataTypeConfiguration)
@@ -46,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors
foreach (string filename in fileNames)
{
if (IsValidFileExtension(filename, _umbracoSettingsSection) == false)
if (IsValidFileExtension(filename, _contentSettings) == false)
{
//we only store a single value for this editor so the 'member' or 'field'
// we'll associate this error with will simply be called 'value'
@@ -55,11 +55,11 @@ namespace Umbraco.Web.PropertyEditors
}
}
internal static bool IsValidFileExtension(string fileName, IUmbracoSettingsSection umbracoSettingsSection)
internal static bool IsValidFileExtension(string fileName, IContentSettings contentSettings)
{
if (fileName.IndexOf('.') <= 0) return false;
var extension = new FileInfo(fileName).Extension.TrimStart(".");
return umbracoSettingsSection.Content.IsFileAllowedForUpload(extension);
return contentSettings.IsFileAllowedForUpload(extension);
}
}
}
@@ -16,14 +16,14 @@ namespace Umbraco.Web.Routing
{
private readonly ILogger _logger;
private readonly IEntityService _entityService;
private readonly IContentSection _contentConfigSection;
private readonly IContentSettings _contentConfigSettings;
private readonly IExamineManager _examineManager;
public ContentFinderByConfigured404(ILogger logger, IEntityService entityService, IContentSection contentConfigSection, IExamineManager examineManager)
public ContentFinderByConfigured404(ILogger logger, IEntityService entityService, IContentSettings contentConfigSettings, IExamineManager examineManager)
{
_logger = logger;
_entityService = entityService;
_contentConfigSection = contentConfigSection;
_contentConfigSettings = contentConfigSettings;
_examineManager = examineManager;
}
@@ -63,7 +63,7 @@ namespace Umbraco.Web.Routing
}
var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId(
_contentConfigSection.Error404Collection.ToArray(),
_contentConfigSettings.Error404Collection.ToArray(),
_entityService,
new PublishedContentQuery(frequest.UmbracoContext.PublishedSnapshot, frequest.UmbracoContext.VariationContextAccessor, _examineManager),
errorCulture);
@@ -24,14 +24,15 @@ namespace Umbraco.Web.Routing
{
private const string _eventStateKey = "Umbraco.Web.Redirects.RedirectTrackingEventHandler";
private readonly IUmbracoSettingsSection _umbracoSettings;
private readonly IWebRoutingSettings _webRoutingSettings;
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IRedirectUrlService _redirectUrlService;
private readonly IVariationContextAccessor _variationContextAccessor;
public RedirectTrackingComponent(IUmbracoSettingsSection umbracoSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor)
public RedirectTrackingComponent(IWebRoutingSettings webRoutingSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor)
{
_umbracoSettings = umbracoSettings;
_webRoutingSettings = webRoutingSettings;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_redirectUrlService = redirectUrlService;
_variationContextAccessor = variationContextAccessor;
@@ -40,7 +41,7 @@ namespace Umbraco.Web.Routing
public void Initialize()
{
// don't let the event handlers kick in if Redirect Tracking is turned off in the config
if (_umbracoSettings.WebRouting.DisableRedirectUrlTracking) return;
if (_webRoutingSettings.DisableRedirectUrlTracking) return;
ContentService.Publishing += ContentService_Publishing;
ContentService.Published += ContentService_Published;
@@ -44,7 +44,6 @@ namespace Umbraco.Core.Runtime
// composers
composition
.ComposeConfiguration()
.ComposeRepositories()
.ComposeServices()
.ComposeCoreMappingProfiles()
@@ -139,7 +138,7 @@ namespace Umbraco.Core.Runtime
composition.RegisterUnique<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
composition.RegisterUnique<IShortStringHelper>(factory
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance<IUmbracoSettingsSection>())));
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance<IRequestHandlerSettings>())));
composition.UrlSegmentProviders()
.Append<DefaultUrlSegmentProvider>();
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
@@ -57,7 +58,7 @@ namespace Umbraco.Core.Runtime
// beware! must use '() => _factory.GetInstance<T>()' and NOT '_factory.GetInstance<T>'
// as the second one captures the current value (null) and therefore fails
_state = new RuntimeState(Logger,
Configs.Settings(), Configs.Global(),
Configs.Global(),
new Lazy<IMainDom>(() => mainDom),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
UmbracoVersion,HostingEnvironment, BackOfficeInfo)
@@ -171,7 +172,7 @@ namespace Umbraco.Core.Runtime
// beware! must use '() => _factory.GetInstance<T>()' and NOT '_factory.GetInstance<T>'
// as the second one captures the current value (null) and therefore fails
_state = new RuntimeState(Logger,
Configs.Settings(), Configs.Global(),
Configs.Global(),
new Lazy<IMainDom>(() => _factory.GetInstance<IMainDom>()),
new Lazy<IServerRegistrar>(() => _factory.GetInstance<IServerRegistrar>()),
UmbracoVersion, HostingEnvironment, BackOfficeInfo)
@@ -369,7 +370,21 @@ namespace Umbraco.Core.Runtime
/// </summary>
/// <returns></returns>
protected virtual ITypeFinder GetTypeFinder()
=> new TypeFinder(Logger);
// TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
// this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
=> new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
// GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website
// in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since
// the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly()
// which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK.
// If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own
// code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting
// from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance
// of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point
// assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one.
// For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are
// getting rid of netframework.
Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()));
/// <summary>
+1 -3
View File
@@ -20,7 +20,6 @@ namespace Umbraco.Core
public class RuntimeState : IRuntimeState
{
private readonly ILogger _logger;
private readonly IUmbracoSettingsSection _settings;
private readonly IGlobalSettings _globalSettings;
private readonly ConcurrentHashSet<string> _applicationUrls = new ConcurrentHashSet<string>();
private readonly Lazy<IMainDom> _mainDom;
@@ -32,13 +31,12 @@ namespace Umbraco.Core
/// <summary>
/// Initializes a new instance of the <see cref="RuntimeState"/> class.
/// </summary>
public RuntimeState(ILogger logger, IUmbracoSettingsSection settings, IGlobalSettings globalSettings,
public RuntimeState(ILogger logger, IGlobalSettings globalSettings,
Lazy<IMainDom> mainDom, Lazy<IServerRegistrar> serverRegistrar, IUmbracoVersion umbracoVersion,
IHostingEnvironment hostingEnvironment,
IBackOfficeInfo backOfficeInfo)
{
_logger = logger;
_settings = settings;
_globalSettings = globalSettings;
_mainDom = mainDom;
_serverRegistrar = serverRegistrar;
@@ -13,12 +13,12 @@ namespace Umbraco.Web.Scheduling
{
private readonly IRuntimeState _runtime;
private readonly IAuditService _auditService;
private readonly IUmbracoSettingsSection _settings;
private readonly ILoggingSettings _settings;
private readonly IProfilingLogger _logger;
private readonly IScopeProvider _scopeProvider;
public LogScrubber(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IRuntimeState runtime, IAuditService auditService, IUmbracoSettingsSection settings, IScopeProvider scopeProvider, IProfilingLogger logger)
IRuntimeState runtime, IAuditService auditService, ILoggingSettings settings, IScopeProvider scopeProvider, IProfilingLogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
@@ -29,13 +29,13 @@ namespace Umbraco.Web.Scheduling
}
// maximum age, in minutes
private int GetLogScrubbingMaximumAge(IUmbracoSettingsSection settings)
private int GetLogScrubbingMaximumAge(ILoggingSettings settings)
{
var maximumAge = 24 * 60; // 24 hours, in minutes
try
{
if (settings.Logging.MaxLogAge > -1)
maximumAge = settings.Logging.MaxLogAge;
if (settings.MaxLogAge > -1)
maximumAge = settings.MaxLogAge;
}
catch (Exception ex)
{
@@ -45,7 +45,7 @@ namespace Umbraco.Web.Scheduling
}
public static int GetLogScrubbingInterval(IUmbracoSettingsSection settings, ILogger logger)
public static int GetLogScrubbingInterval()
{
const int interval = 4 * 60 * 60 * 1000; // 4 hours, in milliseconds
return interval;
@@ -35,10 +35,11 @@ namespace Umbraco.Web.Scheduling
private readonly HealthCheckNotificationMethodCollection _notifications;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly IHealthChecks _healthChecksConfig;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly IServerMessenger _serverMessenger;
private readonly IRequestAccessor _requestAccessor;
private readonly ILoggingSettings _loggingSettings;
private readonly IKeepAliveSettings _keepAliveSettings;
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
@@ -56,7 +57,8 @@ namespace Umbraco.Web.Scheduling
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger,
IHostingEnvironment hostingEnvironment, IHealthChecks healthChecksConfig,
IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor)
IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor,
ILoggingSettings loggingSettings, IKeepAliveSettings keepAliveSettings)
{
_runtime = runtime;
_contentService = contentService;
@@ -69,10 +71,11 @@ namespace Umbraco.Web.Scheduling
_healthChecks = healthChecks;
_notifications = notifications;
_healthChecksConfig = healthChecksConfig ?? throw new ArgumentNullException(nameof(healthChecksConfig));
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper;
_serverMessenger = serverMessenger;
_requestAccessor = requestAccessor;
_loggingSettings = loggingSettings;
_keepAliveSettings = keepAliveSettings;
}
public void Initialize()
@@ -111,17 +114,16 @@ namespace Umbraco.Web.Scheduling
LazyInitializer.EnsureInitialized(ref _tasks, ref _started, ref _locker, () =>
{
_logger.Debug<SchedulerComponent>("Initializing the scheduler");
var settings = _umbracoSettingsSection;
var tasks = new List<IBackgroundTask>();
if (settings.KeepAlive.DisableKeepAliveTask == false)
if (_keepAliveSettings.DisableKeepAliveTask == false)
{
tasks.Add(RegisterKeepAlive(settings.KeepAlive));
tasks.Add(RegisterKeepAlive(_keepAliveSettings));
}
tasks.Add(RegisterScheduledPublishing());
tasks.Add(RegisterLogScrubber(settings));
tasks.Add(RegisterLogScrubber(_loggingSettings));
tasks.Add(RegisterTempFileCleanup());
var healthCheckConfig = _healthChecksConfig;
@@ -132,11 +134,11 @@ namespace Umbraco.Web.Scheduling
});
}
private IBackgroundTask RegisterKeepAlive(IKeepAliveSection keepAliveSection)
private IBackgroundTask RegisterKeepAlive(IKeepAliveSettings keepAliveSettings)
{
// ping/keepalive
// on all servers
var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, keepAliveSection, _logger);
var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, keepAliveSettings, _logger);
_keepAliveRunner.TryAdd(task);
return task;
}
@@ -176,11 +178,11 @@ namespace Umbraco.Web.Scheduling
return task;
}
private IBackgroundTask RegisterLogScrubber(IUmbracoSettingsSection settings)
private IBackgroundTask RegisterLogScrubber(ILoggingSettings settings)
{
// log scrubbing
// install on all, will only run on non-replica servers
var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(settings, _logger), _runtime, _auditService, settings, _scopeProvider, _logger);
var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _runtime, _auditService, settings, _scopeProvider, _logger);
_scrubberRunner.TryAdd(task);
return task;
}
@@ -10,6 +10,7 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Routing;
using Umbraco.Web.Trees;
@@ -50,6 +51,7 @@ namespace Umbraco.Web.Search
/// </summary>
/// <param name="query"></param>
/// <param name="entityType"></param>
/// <param name="culture"></param>
/// <param name="totalFound"></param>
/// <param name="searchFrom">
/// A starting point for the search, generally a node id, but for members this is a member type alias
@@ -62,7 +64,7 @@ namespace Umbraco.Web.Search
string query,
UmbracoEntityTypes entityType,
int pageSize,
long pageIndex, out long totalFound, string searchFrom = null, bool ignoreUserStartNodes = false)
long pageIndex, out long totalFound, string culture = null, string searchFrom = null, bool ignoreUserStartNodes = false)
{
var pagedResult = _backOfficeExamineSearcher.Search(query, entityType, pageSize, pageIndex, out totalFound, searchFrom, ignoreUserStartNodes);
@@ -73,7 +75,7 @@ namespace Umbraco.Web.Search
case UmbracoEntityTypes.Media:
return MediaFromSearchResults(pagedResult);
case UmbracoEntityTypes.Document:
return ContentFromSearchResults(pagedResult);
return ContentFromSearchResults(pagedResult, culture);
default:
throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType);
}
@@ -145,14 +147,20 @@ namespace Umbraco.Web.Search
/// Returns a collection of entities for content based on search results
/// </summary>
/// <param name="results"></param>
/// <param name="culture"></param>
/// <returns></returns>
private IEnumerable<SearchResultEntity> ContentFromSearchResults(IEnumerable<ISearchResult> results)
private IEnumerable<SearchResultEntity> ContentFromSearchResults(IEnumerable<ISearchResult> results, string culture = null)
{
var defaultLang = _languageService.GetDefaultLanguageIsoCode();
foreach (var result in results)
{
var entity = _mapper.Map<SearchResultEntity>(result);
var entity = _mapper.Map<SearchResultEntity>(result, context => {
if(culture != null) {
context.SetCulture(culture);
}
}
);
var intId = entity.Id.TryConvertTo<int>();
if (intId.Success)
@@ -160,7 +168,7 @@ namespace Umbraco.Web.Search
//if it varies by culture, return the default language URL
if (result.Values.TryGetValue(UmbracoExamineFieldNames.VariesByCultureFieldName, out var varies) && varies == "y")
{
entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result, culture: defaultLang);
entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result, culture: culture ?? defaultLang);
}
else
{
@@ -28,16 +28,16 @@ namespace Umbraco.Core.Services.Implement
private readonly ILocalizationService _localizationService;
private readonly INotificationsRepository _notificationsRepository;
private readonly IGlobalSettings _globalSettings;
private readonly IContentSection _contentSection;
private readonly IContentSettings _contentSettings;
private readonly ILogger _logger;
private readonly IIOHelper _ioHelper;
public NotificationService(IScopeProvider provider, IUserService userService, IContentService contentService, ILocalizationService localizationService,
ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSection contentSection)
ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSettings contentSettings)
{
_notificationsRepository = notificationsRepository;
_globalSettings = globalSettings;
_contentSection = contentSection;
_contentSettings = contentSettings;
_uowProvider = provider ?? throw new ArgumentNullException(nameof(provider));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
@@ -302,7 +302,7 @@ namespace Umbraco.Core.Services.Implement
if (content.ContentType.VariesByNothing())
{
if (!_contentSection.DisableHtmlEmail)
if (!_contentSettings.DisableHtmlEmail)
{
//create the HTML summary for invariant content
@@ -344,7 +344,7 @@ namespace Umbraco.Core.Services.Implement
{
//it's variant, so detect what cultures have changed
if (!_contentSection.DisableHtmlEmail)
if (!_contentSettings.DisableHtmlEmail)
{
//Create the HTML based summary (ul of culture names)
@@ -406,13 +406,13 @@ namespace Umbraco.Core.Services.Implement
summary.ToString());
// create the mail message
var mail = new MailMessage(_contentSection.NotificationEmailAddress, mailingUser.Email);
var mail = new MailMessage(_contentSettings.NotificationEmailAddress, mailingUser.Email);
// populate the message
mail.Subject = createSubject((mailingUser, subjectVars));
if (_contentSection.DisableHtmlEmail)
if (_contentSettings.DisableHtmlEmail)
{
mail.IsBodyHtml = false;
mail.Body = createBody((user: mailingUser, body: bodyVars, false));
@@ -1179,7 +1179,7 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Occurs before Save
/// </summary>
internal static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavingUserGroup;
public static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavingUserGroup;
/// <summary>
/// Occurs after Save
@@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.8.14" />
<PackageReference Include="LightInject" Version="6.2.0" />
<PackageReference Include="LightInject" Version="6.3.2" />
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="Markdown" Version="2.2.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
@@ -94,7 +94,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building
//
private static void WriteGeneratedCodeAttribute(StringBuilder sb, string tabs)
{
sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder\", \"{1}\")]\n", tabs, ApiVersion.Current.Version);
sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder.Embedded\", \"{1}\")]\n", tabs, ApiVersion.Current.Version);
}
private void WriteContentType(StringBuilder sb, TypeModel type)
@@ -14,7 +14,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building
sb.Append("// <auto-generated>\n");
sb.Append("// This code was generated by a tool.\n");
sb.Append("//\n");
sb.AppendFormat("// Umbraco.ModelsBuilder v{0}\n", ApiVersion.Current.Version);
sb.AppendFormat("// Umbraco.ModelsBuilder.Embedded v{0}\n", ApiVersion.Current.Version);
sb.Append("//\n");
sb.Append("// Changes to this file will be lost if the code is regenerated.\n");
sb.Append("// </auto-generated>\n");
@@ -2,7 +2,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Umbraco.ModelsBuilder")]
[assembly: AssemblyTitle("Umbraco.ModelsBuilder.Embedded")]
[assembly: AssemblyDescription("Umbraco ModelsBuilder")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("Umbraco CMS")]
@@ -0,0 +1,30 @@
using BenchmarkDotNet.Attributes;
using System;
using System.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Tests.Benchmarks.Config;
namespace Umbraco.Tests.Benchmarks
{
[MediumRunJob]
[MemoryDiagnoser]
public class TypeFinderBenchmarks
{
[Benchmark(Baseline = true)]
public void WithGetReferencingAssembliesCheck()
{
var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
var found = typeFinder1.FindClassesOfType<IDiscoverable>().Count();
}
[Benchmark]
public void WithoutGetReferencingAssembliesCheck()
{
var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly));
typeFinder2.QueryWithReferencingAssemblies = false;
var found = typeFinder2.FindClassesOfType<IDiscoverable>().Count();
}
}
}
@@ -61,6 +61,7 @@
<Compile Include="SqlTemplatesBenchmark.cs" />
<Compile Include="StringReplaceManyBenchmarks.cs" />
<Compile Include="TryConvertToBenchmarks.cs" />
<Compile Include="TypeFinderBenchmarks.cs" />
<Compile Include="XmlBenchmarks.cs" />
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,178 @@
using Moq;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Tests.Common
{
public class SettingsForTests
{
public SettingsForTests()
{
}
public IGlobalSettings GenerateMockGlobalSettings(IUmbracoVersion umbVersion, IIOHelper ioHelper)
{
var config = Mock.Of<IGlobalSettings>(
settings =>
settings.ConfigurationStatus == umbVersion.SemanticVersion.ToSemanticString() &&
settings.UseHttps == false &&
settings.HideTopLevelNodeFromPath == false &&
settings.Path == ioHelper.ResolveUrl("~/umbraco") &&
settings.TimeOutInMinutes == 20 &&
settings.DefaultUILanguage == "en" &&
settings.ReservedPaths == (GlobalSettings.StaticReservedPaths + "~/umbraco") &&
settings.ReservedUrls == GlobalSettings.StaticReservedUrls &&
settings.UmbracoPath == "~/umbraco" &&
settings.UmbracoMediaPath == "~/media" &&
settings.UmbracoCssPath == "~/css" &&
settings.UmbracoScriptsPath == "~/scripts"
);
return config;
}
/// <summary>
/// Returns generated settings which can be stubbed to return whatever values necessary
/// </summary>
/// <returns></returns>
public IContentSettings GenerateMockContentSettings()
{
var content = new Mock<IContentSettings>();
//Now configure some defaults - the defaults in the config section classes do NOT pertain to the mocked data!!
content.Setup(x => x.ImageAutoFillProperties).Returns(ContentImagingElement.GetDefaultImageAutoFillProperties());
content.Setup(x => x.ImageFileTypes).Returns(ContentImagingElement.GetDefaultImageFileTypes());
return content.Object;
}
//// from appSettings
//private readonly IDictionary<string, string> SavedAppSettings = new Dictionary<string, string>();
//static void SaveSetting(string key)
//{
// SavedAppSettings[key] = ConfigurationManager.AppSettings[key];
//}
//static void SaveSettings()
//{
// SaveSetting("umbracoHideTopLevelNodeFromPath");
// SaveSetting("umbracoUseDirectoryUrls");
// SaveSetting("umbracoPath");
// SaveSetting("umbracoReservedPaths");
// SaveSetting("umbracoReservedUrls");
// SaveSetting("umbracoConfigurationStatus");
//}
// reset & defaults
//static SettingsForTests()
//{
// //SaveSettings();
//}
public void Reset()
{
ResetSettings();
GlobalSettings.Reset();
//foreach (var kvp in SavedAppSettings)
// ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value);
//// set some defaults that are wrong in the config file?!
//// this is annoying, really
//HideTopLevelNodeFromPath = false;
}
/// <summary>
/// This sets all settings back to default settings
/// </summary>
private void ResetSettings()
{
_defaultGlobalSettings = null;
}
private IGlobalSettings _defaultGlobalSettings;
private IHostingSettings _defaultHostingSettings;
public IGlobalSettings GetDefaultGlobalSettings(IUmbracoVersion umbVersion, IIOHelper ioHelper)
{
if (_defaultGlobalSettings == null)
{
_defaultGlobalSettings = GenerateMockGlobalSettings(umbVersion, ioHelper);
}
return _defaultGlobalSettings;
}
public IHostingSettings GetDefaultHostingSettings()
{
if (_defaultHostingSettings == null)
{
_defaultHostingSettings = GenerateMockHostingSettings();
}
return _defaultHostingSettings;
}
private IHostingSettings GenerateMockHostingSettings()
{
var config = Mock.Of<IHostingSettings>(
settings =>
settings.LocalTempStorageLocation == LocalTempStorage.EnvironmentTemp &&
settings.DebugMode == false
);
return config;
}
public IWebRoutingSettings GenerateMockWebRoutingSettings()
{
var mock = new Mock<IWebRoutingSettings>();
mock.Setup(x => x.DisableRedirectUrlTracking).Returns(false);
mock.Setup(x => x.InternalRedirectPreservesTemplate).Returns(false);
mock.Setup(x => x.UrlProviderMode).Returns(UrlMode.Auto.ToString());
return mock.Object;
}
public IRequestHandlerSettings GenerateMockRequestHandlerSettings()
{
var mock = new Mock<IRequestHandlerSettings>();
mock.Setup(x => x.AddTrailingSlash).Returns(true);
mock.Setup(x => x.ConvertUrlsToAscii).Returns(false);
mock.Setup(x => x.TryConvertUrlsToAscii).Returns(false);
mock.Setup(x => x.CharCollection).Returns(RequestHandlerElement.GetDefaultCharReplacements);
return mock.Object;
}
public ISecuritySettings GenerateMockSecuritySettings()
{
var security = new Mock<ISecuritySettings>();
return security.Object;
}
public IUserPasswordConfiguration GenerateMockUserPasswordConfiguration()
{
var mock = new Mock<IUserPasswordConfiguration>();
return mock.Object;
}
public IMemberPasswordConfiguration GenerateMockMemberPasswordConfiguration()
{
var mock = new Mock<IMemberPasswordConfiguration>();
return mock.Object;
}
}
}
@@ -1,6 +1,6 @@
using Umbraco.Web.PublishedCache;
namespace Umbraco.Tests.Testing.Objects.Accessors
namespace Umbraco.Tests.Common
{
public class TestDefaultCultureAccessor : IDefaultCultureAccessor
{
+144
View File
@@ -0,0 +1,144 @@
using System;
using System.IO;
using Moq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Diagnostics;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Runtime;
using Umbraco.Core.Serialization;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Net;
using Umbraco.Web;
using Umbraco.Web.Routing;
namespace Umbraco.Tests.Common
{
/// <summary>
/// Common helper properties and methods useful to testing
/// </summary>
public abstract class TestHelperBase
{
public TestHelperBase()
{
SettingsForTests = new SettingsForTests();
IOHelper = new IOHelper(GetHostingEnvironment());
MainDom = new MainDom(Mock.Of<ILogger>(), GetHostingEnvironment(), new MainDomSemaphoreLock(Mock.Of<ILogger>(), GetHostingEnvironment()));
UriUtility = new UriUtility(GetHostingEnvironment());
}
public ITypeFinder GetTypeFinder()
{
var typeFinder = new TypeFinder(Mock.Of<ILogger>(),
new DefaultUmbracoAssemblyProvider(typeof(TestHelperBase).Assembly));
return typeFinder;
}
public TypeLoader GetMockedTypeLoader()
{
return new TypeLoader(IOHelper, Mock.Of<ITypeFinder>(), Mock.Of<IAppPolicyCache>(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of<IProfilingLogger>());
}
public Configs GetConfigs()
{
return GetConfigsFactory().Create(IOHelper, Mock.Of<ILogger>());
}
public IRuntimeState GetRuntimeState()
{
return new RuntimeState(
Mock.Of<ILogger>(),
Mock.Of<IGlobalSettings>(),
new Lazy<IMainDom>(),
new Lazy<IServerRegistrar>(),
GetUmbracoVersion(),
GetHostingEnvironment(),
GetBackOfficeInfo()
);
}
public abstract IBackOfficeInfo GetBackOfficeInfo();
public IConfigsFactory GetConfigsFactory()
{
return new ConfigsFactory();
}
/// <summary>
/// Gets the current assembly directory.
/// </summary>
/// <value>The assembly directory.</value>
public string CurrentAssemblyDirectory
{
get
{
var codeBase = typeof(TestHelperBase).Assembly.CodeBase;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
return Path.GetDirectoryName(path);
}
}
public IShortStringHelper ShortStringHelper { get; } = new DefaultShortStringHelper(new DefaultShortStringHelperConfig());
public IJsonSerializer JsonSerializer { get; } = new JsonNetSerializer();
public IVariationContextAccessor VariationContextAccessor { get; } = new TestVariationContextAccessor();
public abstract IDbProviderFactoryCreator DbProviderFactoryCreator { get; }
public abstract IBulkSqlInsertProvider BulkSqlInsertProvider { get; }
public abstract IMarchal Marchal { get; }
public ICoreDebug CoreDebug { get; } = new CoreDebug();
public IIOHelper IOHelper { get; }
public IMainDom MainDom { get; }
public UriUtility UriUtility { get; }
public SettingsForTests SettingsForTests { get; }
public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings();
/// <summary>
/// Maps the given <paramref name="relativePath"/> making it rooted on <see cref="CurrentAssemblyDirectory"/>. <paramref name="relativePath"/> must start with <code>~/</code>
/// </summary>
/// <param name="relativePath">The relative path.</param>
/// <returns></returns>
public string MapPathForTest(string relativePath)
{
if (!relativePath.StartsWith("~/"))
throw new ArgumentException("relativePath must start with '~/'", "relativePath");
return relativePath.Replace("~/", CurrentAssemblyDirectory + "/");
}
public IUmbracoVersion GetUmbracoVersion()
{
return new UmbracoVersion(GetConfigs().Global());
}
public IRegister GetRegister()
{
return RegisterFactory.Create(GetConfigs().Global());
}
public abstract IHostingEnvironment GetHostingEnvironment();
public abstract IIpResolver GetIpResolver();
public IRequestCache GetRequestCache()
{
return new DictionaryAppCache();
}
public IPublishedUrlProvider GetPublishedUrlProvider()
{
var mock = new Mock<IPublishedUrlProvider>();
return mock.Object;
}
}
}
@@ -1,6 +1,6 @@
using Umbraco.Web.PublishedCache;
namespace Umbraco.Tests.Testing.Objects.Accessors
namespace Umbraco.Tests.Common
{
public class TestPublishedSnapshotAccessor : IPublishedSnapshotAccessor
{

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