Merge pull request #7095 from umbraco/netcore/feature/AB3594_move_exsiting_configuration_to_own_project

Netcore: Move configuration
This commit is contained in:
Shannon Deminick
2019-11-19 11:49:21 +11:00
committed by GitHub
217 changed files with 1629 additions and 1189 deletions

View File

@@ -5,9 +5,9 @@
<sectionGroup name="applicationSettings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<sectionGroup name="system.web.webPages.razor" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing">
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Configuration" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="dashBoard" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Configuration" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</sectionGroup>
</configSections>

View File

@@ -27,19 +27,12 @@ namespace Umbraco.Core.Composing
/// <param name="logger">A logger.</param>
/// <param name="runtimeState">The runtime state.</param>
/// <param name="configs">Optional configs.</param>
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs = null)
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs)
{
_register = register;
TypeLoader = typeLoader;
Logger = logger;
RuntimeState = runtimeState;
if (configs == null)
{
configs = new Configs();
configs.AddCoreConfigs();
}
Configs = configs;
}
@@ -131,12 +124,14 @@ namespace Umbraco.Core.Composing
builder.RegisterWith(_register);
_builders.Clear(); // no point keep them around
Configs.RegisterWith(_register);
IFactory factory = null;
Configs.RegisterWith(_register, () => factory);
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
factory = _register.CreateFactory();
return factory;
}

View File

@@ -0,0 +1,40 @@
using System;
using System.IO;
using System.Linq;
using Umbraco.Core.Configuration;
namespace Umbraco.Core
{
public static class ConfigConnectionStringExtensions
{
public static bool IsConnectionStringConfigured(this ConfigConnectionString databaseSettings)
{
var dbIsSqlCe = false;
if (databaseSettings?.ProviderName != null)
dbIsSqlCe = databaseSettings.ProviderName == Constants.DbProviderNames.SqlCe;
var sqlCeDatabaseExists = false;
if (dbIsSqlCe)
{
var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source="));
if (dataSourcePart != null)
{
var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString());
var filePath = datasource.Replace("Data Source=", string.Empty);
sqlCeDatabaseExists = File.Exists(filePath);
}
}
// Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet
if (databaseSettings == null
|| string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName)
|| (dbIsSqlCe && sqlCeDatabaseExists == false))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Umbraco.Core.Configuration
{
public class ConfigConnectionString
{
public ConfigConnectionString(string connectionString, string providerName, string name)
{
ConnectionString = connectionString;
ProviderName = providerName;
Name = name;
}
public string ConnectionString { get; }
public string ProviderName { get; }
public string Name { get; }
}
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
@@ -15,8 +13,16 @@ namespace Umbraco.Core.Configuration
/// </remarks>
public class Configs
{
private readonly Func<string, object> _configSectionResolver;
public Configs(Func<string, object> configSectionResolver)
{
_configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver));
}
private readonly Dictionary<Type, Lazy<object>> _configs = new Dictionary<Type, Lazy<object>>();
private Dictionary<Type, Action<IRegister>> _registerings = new Dictionary<Type, Action<IRegister>>();
private Lazy<IFactory> _factory;
/// <summary>
/// Gets a configuration.
@@ -60,7 +66,7 @@ namespace Umbraco.Core.Configuration
_configs[typeOfConfig] = new Lazy<object>(() =>
{
if (Current.HasFactory) return Current.Factory.GetInstance<TConfig>();
if (!(_factory is null)) return _factory.Value.GetInstance<TConfig>();
throw new InvalidOperationException($"Cannot get configuration of type {typeOfConfig} during composition.");
});
_registerings[typeOfConfig] = register => register.Register(configFactory, Lifetime.Singleton);
@@ -75,7 +81,7 @@ namespace Umbraco.Core.Configuration
Add(() => GetConfig<TConfig>(sectionName));
}
private static TConfig GetConfig<TConfig>(string sectionName)
private TConfig GetConfig<TConfig>(string sectionName)
where TConfig : class
{
// note: need to use SafeCallContext here because ConfigurationManager.GetSection ends up getting AppDomain.Evidence
@@ -83,10 +89,9 @@ namespace Umbraco.Core.Configuration
using (new SafeCallContext())
{
if ((ConfigurationManager.GetSection(sectionName) is TConfig config))
if ((_configSectionResolver(sectionName) is TConfig config))
return config;
var ex = new ConfigurationErrorsException($"Could not get configuration section \"{sectionName}\" from config files.");
Current.Logger.Error<Configs>(ex, "Config error");
var ex = new InvalidOperationException($"Could not get configuration section \"{sectionName}\" from config files.");
throw ex;
}
}
@@ -94,12 +99,14 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Registers configurations in a register.
/// </summary>
public void RegisterWith(IRegister register)
public void RegisterWith(IRegister register, Func<IFactory> factory)
{
// do it only once
if (_registerings == null)
throw new InvalidOperationException("Configurations have already been registered.");
_factory = new Lazy<IFactory>(factory);
register.Register(this);
foreach (var registering in _registerings.Values)

View File

@@ -19,6 +19,9 @@ namespace Umbraco.Core
public static IGlobalSettings Global(this Configs configs)
=> configs.GetConfig<IGlobalSettings>();
public static IConnectionStrings ConnectionStrings(this Configs configs)
=> configs.GetConfig<IConnectionStrings>();
public static IUmbracoSettingsSection Settings(this Configs configs)
=> configs.GetConfig<IUmbracoSettingsSection>();
@@ -28,25 +31,20 @@ namespace Umbraco.Core
public static IGridConfig Grids(this Configs configs)
=> configs.GetConfig<IGridConfig>();
internal static CoreDebug CoreDebug(this Configs configs)
=> configs.GetConfig<CoreDebug>();
public static ICoreDebug CoreDebug(this Configs configs)
=> configs.GetConfig<ICoreDebug>();
public static void AddCoreConfigs(this Configs configs)
public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper)
{
var configDir = new DirectoryInfo(Current.IOHelper.MapPath(Constants.SystemDirectories.Config));
var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config));
configs.Add<IGlobalSettings>(() => new GlobalSettings());
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
configs.Add(() => new CoreDebug());
// GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition
configs.Add<IGridConfig>(factory => new GridConfig(
factory.GetInstance<ILogger>(),
factory.GetInstance<AppCaches>(),
configDir,
factory.GetInstance<ManifestParser>(),
factory.GetInstance<IManifestParser>(),
factory.GetInstance<IRuntimeState>().Debug));
}
}

View File

@@ -0,0 +1,45 @@
using System;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public static class GlobalSettingsExtensions
{
private static string _mvcArea;
/// <summary>
/// This returns the string of the MVC Area route.
/// </summary>
/// <remarks>
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
///
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
/// </remarks>
public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IIOHelper ioHelper)
{
if (_mvcArea != null) return _mvcArea;
_mvcArea = GetUmbracoMvcAreaNoCache(globalSettings, ioHelper);
return _mvcArea;
}
internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IIOHelper ioHelper)
{
if (globalSettings.Path.IsNullOrWhiteSpace())
{
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
}
var path = globalSettings.Path;
if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518
path = path.Substring(ioHelper.Root.Length);
return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
}
}
}

View File

@@ -5,9 +5,9 @@ using Umbraco.Core.Manifest;
namespace Umbraco.Core.Configuration.Grid
{
class GridConfig : IGridConfig
public class GridConfig : IGridConfig
{
public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, ManifestParser manifestParser, bool isDebug)
public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
{
EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug);
}

View File

@@ -13,10 +13,10 @@ namespace Umbraco.Core.Configuration.Grid
private readonly ILogger _logger;
private readonly AppCaches _appCaches;
private readonly DirectoryInfo _configFolder;
private readonly ManifestParser _manifestParser;
private readonly IManifestParser _manifestParser;
private readonly bool _isDebug;
public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, ManifestParser manifestParser, bool isDebug)
public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
{
_logger = logger;
_appCaches = appCaches;
@@ -29,9 +29,9 @@ namespace Umbraco.Core.Configuration.Grid
{
get
{
List<GridEditor> GetResult()
List<IGridEditorConfig> GetResult()
{
var editors = new List<GridEditor>();
var editors = new List<IGridEditorConfig>();
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Configuration.Grid
//cache the result if debugging is disabled
var result = _isDebug
? GetResult()
: _appCaches.RuntimeCache.GetCacheItem<List<GridEditor>>(typeof(GridEditorsConfig) + ".Editors",GetResult, TimeSpan.FromMinutes(10));
: _appCaches.RuntimeCache.GetCacheItem<List<IGridEditorConfig>>(typeof(GridEditorsConfig) + ".Editors",GetResult, TimeSpan.FromMinutes(10));
return result;
}

View File

@@ -1,7 +1,10 @@
namespace Umbraco.Core.Configuration.HealthChecks
using System.Runtime.Serialization;
namespace Umbraco.Core.Configuration.HealthChecks
{
public enum HealthCheckNotificationVerbosity
{
Summary,
Detailed
}

View File

@@ -0,0 +1,7 @@
namespace Umbraco.Core.Configuration
{
public interface IConfigsFactory
{
Configs Create();
}
}

View File

@@ -0,0 +1,10 @@
namespace Umbraco.Core.Configuration
{
public interface IConnectionStrings
{
ConfigConnectionString this[string key]
{
get;
}
}
}

View File

@@ -0,0 +1,17 @@
namespace Umbraco.Core.Configuration
{
public interface ICoreDebug
{
/// <summary>
/// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed.
/// this helps troubleshooting rogue scopes that we forget to complete
/// </summary>
bool LogUncompletedScopes { get; }
/// <summary>
/// When set to true, the Logger creates a mini dump of w3wp in ~/App_Data/MiniDump whenever it logs
/// an error due to a ThreadAbortException that is due to a timeout.
/// </summary>
bool DumpOnTimeoutThreadAbort { get; }
}
}

View File

@@ -5,6 +5,9 @@
/// </summary>
public interface IGlobalSettings
{
// fixme: Review this class, it is now just a dumping ground for config options (based basically on whatever might be in appSettings),
// our config classes should be named according to what they are configuring.
/// <summary>
/// Gets the reserved urls from web.config.
/// </summary>
@@ -63,14 +66,39 @@
/// </summary>
LocalTempStorage LocalTempStorageLocation { get; }
/// <summary>
/// Gets the location of temporary files.
/// </summary>
string LocalTempPath { get; }
string UmbracoPath { get; }
string UmbracoCssPath { get; }
string UmbracoScriptsPath { get; }
string UmbracoMediaPath { get; }
bool DebugMode { get; }
bool IsSmtpServerConfigured { get; }
/// <summary>
/// Gets a value indicating whether the runtime should enter Install level when the database is missing.
/// </summary>
/// <remarks>
/// <para>By default, when a database connection string is configured but it is not possible to
/// connect to the database, the runtime enters the BootFailed level. If this options is set to true,
/// it enters the Install level instead.</para>
/// <para>It is then up to the implementor, that is setting this value, to take over the installation
/// sequence.</para>
/// </remarks>
bool InstallMissingDatabase { get; }
/// <summary>
/// Gets a value indicating whether the runtime should enter Install level when the database is empty.
/// </summary>
/// <remarks>
/// <para>By default, when a database connection string is configured and it is possible to connect to
/// the database, but the database is empty, the runtime enters the BootFailed level. If this options
/// is set to true, it enters the Install level instead.</para>
/// <para>It is then up to the implementor, that is setting this value, to take over the installation
/// sequence.</para>
/// </remarks>
bool InstallEmptyDatabase { get; }
bool DisableElectionForSingleServer { get; }
string RegisterType { get; }
string DatabaseFactoryServerVersion { get; }
}
}

View File

@@ -0,0 +1,56 @@
using System;
using Semver;
namespace Umbraco.Core.Configuration
{
public interface IUmbracoVersion
{
/// <summary>
/// Gets the non-semantic version of the Umbraco code.
/// </summary>
Version Current { get; }
/// <summary>
/// Gets the semantic version comments of the Umbraco code.
/// </summary>
string Comment { get; }
/// <summary>
/// Gets the assembly version of the Umbraco code.
/// </summary>
/// <remarks>
/// <para>The assembly version is the value of the <see cref="AssemblyVersionAttribute"/>.</para>
/// <para>Is the one that the CLR checks for compatibility. Therefore, it changes only on
/// hard-breaking changes (for instance, on new major versions).</para>
/// </remarks>
Version AssemblyVersion { get; }
/// <summary>
/// Gets the assembly file version of the Umbraco code.
/// </summary>
/// <remarks>
/// <para>The assembly version is the value of the <see cref="AssemblyFileVersionAttribute"/>.</para>
/// </remarks>
Version AssemblyFileVersion { get; }
/// <summary>
/// Gets the semantic version of the Umbraco code.
/// </summary>
/// <remarks>
/// <para>The semantic version is the value of the <see cref="AssemblyInformationalVersionAttribute"/>.</para>
/// <para>It is the full version of Umbraco, including comments.</para>
/// </remarks>
SemVersion SemanticVersion { get; }
/// <summary>
/// Gets the "local" version of the site.
/// </summary>
/// <remarks>
/// <para>Three things have a version, really: the executing code, the database model,
/// and the site/files. The database model version is entirely managed via migrations,
/// and changes during an upgrade. The executing code version changes when new code is
/// deployed. The site/files version changes during an upgrade.</para>
/// </remarks>
SemVersion LocalVersion { get; }
}
}

View File

@@ -8,11 +8,19 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Represents the version of the executing code.
/// </summary>
public static class UmbracoVersion
public class UmbracoVersion : IUmbracoVersion
{
static UmbracoVersion()
private readonly IGlobalSettings _globalSettings;
public UmbracoVersion(IGlobalSettings globalSettings)
:this()
{
var umbracoCoreAssembly = typeof(UmbracoVersion).Assembly;
_globalSettings = globalSettings;
}
public UmbracoVersion()
{
var umbracoCoreAssembly = typeof(SemVersion).Assembly;
// gets the value indicated by the AssemblyVersion attribute
AssemblyVersion = umbracoCoreAssembly.GetName().Version;
@@ -32,12 +40,12 @@ namespace Umbraco.Core.Configuration
/// Gets the non-semantic version of the Umbraco code.
/// </summary>
// TODO: rename to Version
public static Version Current { get; }
public Version Current { get; }
/// <summary>
/// Gets the semantic version comments of the Umbraco code.
/// </summary>
public static string Comment => SemanticVersion.Prerelease;
public string Comment => SemanticVersion.Prerelease;
/// <summary>
/// Gets the assembly version of the Umbraco code.
@@ -47,7 +55,7 @@ namespace Umbraco.Core.Configuration
/// <para>Is the one that the CLR checks for compatibility. Therefore, it changes only on
/// hard-breaking changes (for instance, on new major versions).</para>
/// </remarks>
public static Version AssemblyVersion {get; }
public Version AssemblyVersion {get; }
/// <summary>
/// Gets the assembly file version of the Umbraco code.
@@ -55,7 +63,7 @@ namespace Umbraco.Core.Configuration
/// <remarks>
/// <para>The assembly version is the value of the <see cref="AssemblyFileVersionAttribute"/>.</para>
/// </remarks>
public static Version AssemblyFileVersion { get; }
public Version AssemblyFileVersion { get; }
/// <summary>
/// Gets the semantic version of the Umbraco code.
@@ -64,7 +72,7 @@ namespace Umbraco.Core.Configuration
/// <para>The semantic version is the value of the <see cref="AssemblyInformationalVersionAttribute"/>.</para>
/// <para>It is the full version of Umbraco, including comments.</para>
/// </remarks>
public static SemVersion SemanticVersion { get; }
public SemVersion SemanticVersion { get; }
/// <summary>
/// Gets the "local" version of the site.
@@ -75,21 +83,11 @@ namespace Umbraco.Core.Configuration
/// and changes during an upgrade. The executing code version changes when new code is
/// deployed. The site/files version changes during an upgrade.</para>
/// </remarks>
public static SemVersion LocalVersion
{
public SemVersion LocalVersion {
get
{
try
{
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus];
return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
}
catch
{
return null;
}
}
}
var value = _globalSettings.ConfigurationStatus;
return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
} }
}
}

View File

@@ -100,7 +100,7 @@ namespace Umbraco.Core.Events
public IEnumerable<TEntity> DeletedEntities
{
get => EventObject;
internal set => EventObject = value;
set => EventObject = value;
}
/// <summary>

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Umbraco.Core.Models;
namespace Umbraco.Core.Events
{

View File

@@ -3,7 +3,7 @@
/// <summary>
/// A simple/default transient messages factory
/// </summary>
internal class TransientEventMessagesFactory : IEventMessagesFactory
public class TransientEventMessagesFactory : IEventMessagesFactory
{
public EventMessages Get()
{

View File

@@ -19,6 +19,7 @@ namespace Umbraco.Core.IO
string MapPath(string path, bool useHttpContext);
string MapPath(string path);
/// <summary>
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
/// </summary>

View File

@@ -7,6 +7,13 @@ namespace Umbraco.Core.Logging
/// </summary>
public class DebugDiagnosticsLogger : ILogger
{
private readonly IMessageTemplates _messageTemplates;
public DebugDiagnosticsLogger(IMessageTemplates messageTemplates)
{
_messageTemplates = messageTemplates;
}
public bool IsEnabled(Type reporting, LogLevel level)
=> true;
@@ -31,7 +38,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
@@ -61,7 +68,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
@@ -79,7 +86,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Warn(Type reporting, string message, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(message, propertyValues), reporting.FullName);
}
/// <inheritdoc/>
@@ -91,7 +98,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message + Environment.NewLine + exception, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(message + Environment.NewLine + exception, propertyValues), reporting.FullName);
}
/// <inheritdoc/>
@@ -103,7 +110,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Info(Type reporting, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
}
/// <inheritdoc/>
@@ -115,7 +122,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Debug(Type reporting, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
}
/// <inheritdoc/>
@@ -127,7 +134,7 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Provides tools to support message templates.
/// </summary>
public interface IMessageTemplates
{
string Render(string messageTemplate, params object[] args);
}
}

View File

@@ -6,7 +6,7 @@ namespace Umbraco.Core.Logging
/// <summary>
/// Implements <see cref="IProfiler"/> by writing profiling results to an <see cref="ILogger"/>.
/// </summary>
internal class LogProfiler : IProfiler
public class LogProfiler : IProfiler
{
private readonly ILogger _logger;

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Logging
{
internal class VoidProfiler : IProfiler
public class VoidProfiler : IProfiler
{
private readonly VoidDisposable _disposable = new VoidDisposable();

View File

@@ -11,7 +11,6 @@ namespace Umbraco.Core.Models.Entities
{
var now = DateTime.Now;
// just in case
if (entity.CreateDate == default)
{
entity.CreateDate = now;

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core
{
internal static class NameValueCollectionExtensions
public static class NameValueCollectionExtensions
{
public static IEnumerable<KeyValuePair<string, string>> AsEnumerable(this NameValueCollection nvc)
{

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: Guid("DA322714-FB89-4943-92BD-BB122B82F66B")]
// Umbraco Cms
[assembly: InternalsVisibleTo("Umbraco.Web")]
[assembly: InternalsVisibleTo("Umbraco.Web.UI")]
[assembly: InternalsVisibleTo("Umbraco.Examine")]
[assembly: InternalsVisibleTo("Umbraco.ModelsBuilder.Embedded")]
[assembly: InternalsVisibleTo("Umbraco.Tests")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")]
// Allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
// Umbraco Deploy
[assembly: InternalsVisibleTo("Umbraco.Deploy")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.UI")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.Cloud")]
// Umbraco Forms
[assembly: InternalsVisibleTo("Umbraco.Forms.Core")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
// Umbraco Headless
[assembly: InternalsVisibleTo("Umbraco.Cloud.Headless")]
// code analysis
// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")]

View File

@@ -3,7 +3,7 @@
/// <summary>
/// Marker interface for any editor configuration that supports Ignoring user start nodes
/// </summary>
internal interface IIgnoreUserStartNodesConfig
public interface IIgnoreUserStartNodesConfig
{
bool IgnoreUserStartNodes { get; set; }
}

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
namespace Umbraco.Core
{

View File

@@ -4,6 +4,10 @@
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>7.3</LangVersion>
<RootNamespace>Umbraco.Core</RootNamespace>
<AssemblyVersion>9.0.0</AssemblyVersion>
<InformationalVersion>9.0.0</InformationalVersion>
<FileVersion>9.0.0</FileVersion>
<Product>Umbraco CMS</Product>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,34 @@
using System.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public class ConfigsFactory : IConfigsFactory
{
private readonly IIOHelper _ioHelper;
public ConfigsFactory(IIOHelper ioHelper)
{
_ioHelper = ioHelper;
GlobalSettings = new GlobalSettings(_ioHelper);
}
public IGlobalSettings GlobalSettings { get; }
public Configs Create()
{
var configs = new Configs(section => ConfigurationManager.GetSection(section));
configs.Add<IGlobalSettings>(() => GlobalSettings);
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
configs.Add<ICoreDebug>(() => new CoreDebug());
configs.Add<IConnectionStrings>(() => new ConnectionStrings());
configs.AddCoreConfigs(_ioHelper);
return configs;
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Configuration;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public class ConnectionStrings : IConnectionStrings
{
public ConfigConnectionString this[string key]
{
get
{
var settings = ConfigurationManager.ConnectionStrings[key];
return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name);
}
}
}
}

View File

@@ -1,22 +1,21 @@
using System;
using System.Configuration;
namespace Umbraco.Core.Configuration
{
internal class CoreDebug
public class CoreDebug : ICoreDebug
{
public CoreDebug()
{
var appSettings = System.Configuration.ConfigurationManager.AppSettings;
var appSettings = ConfigurationManager.AppSettings;
LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase);
DumpOnTimeoutThreadAbort = string.Equals("true", appSettings[Constants.AppSettings.Debug.DumpOnTimeoutThreadAbort], StringComparison.OrdinalIgnoreCase);
}
// when true, Scope logs the stack trace for any scope that gets disposed without being completed.
// this helps troubleshooting rogue scopes that we forget to complete
/// <inheritdoc />
public bool LogUncompletedScopes { get; }
// when true, the Logger creates a mini dump of w3wp in ~/App_Data/MiniDump whenever it logs
// an error due to a ThreadAbortException that is due to a timeout.
/// <inheritdoc />
public bool DumpOnTimeoutThreadAbort { get; }
}
}

View File

@@ -1,12 +1,7 @@
using System;
using System.Configuration;
using System.Linq;
using System.Net.Configuration;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Xml.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
@@ -19,6 +14,7 @@ namespace Umbraco.Core.Configuration
/// </summary>
public class GlobalSettings : IGlobalSettings
{
private readonly IIOHelper _ioHelper;
private string _localTempPath;
// TODO these should not be static
@@ -29,6 +25,11 @@ namespace Umbraco.Core.Configuration
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
public GlobalSettings(IIOHelper ioHelper)
{
_ioHelper = ioHelper;
}
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
/// </summary>
@@ -47,20 +48,42 @@ namespace Umbraco.Core.Configuration
{
ResetInternal();
}
public static bool HasSmtpServerConfigured(string appPath)
public bool IsSmtpServerConfigured
{
if (HasSmtpServer.HasValue) return HasSmtpServer.Value;
get
{
var smtpSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp") as ConfigurationSection;
if (smtpSection is null) return false;
var config = WebConfigurationManager.OpenWebConfiguration(appPath);
var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
// note: "noreply@example.com" is/was the sample SMTP from email - we'll regard that as "not configured"
if (settings == null || settings.Smtp == null || "noreply@example.com".Equals(settings.Smtp.From, StringComparison.OrdinalIgnoreCase)) return false;
if (settings.Smtp.SpecifiedPickupDirectory != null && string.IsNullOrEmpty(settings.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation) == false)
return true;
if (settings.Smtp.Network != null && string.IsNullOrEmpty(settings.Smtp.Network.Host) == false)
return true;
return false;
var from = smtpSection.ElementInformation.Properties["from"];
if (@from != null
&& @from.Value is string fromPropValue
&& string.IsNullOrEmpty(fromPropValue) == false
&& !string.Equals("noreply@example.com", fromPropValue, StringComparison.OrdinalIgnoreCase))
{
return true;
}
var networkSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp/network") as ConfigurationSection;
var host = networkSection?.ElementInformation.Properties["host"];
if (host != null
&& host.Value is string hostPropValue
&& string.IsNullOrEmpty(hostPropValue) == false)
{
return true;
}
var specifiedPickupDirectorySection = ConfigurationManager.GetSection("system.net/mailSettings/smtp/specifiedPickupDirectory") as ConfigurationSection;
var pickupDirectoryLocation = specifiedPickupDirectorySection?.ElementInformation.Properties["pickupDirectoryLocation"];
if (pickupDirectoryLocation != null
&& pickupDirectoryLocation.Value is string pickupDirectoryLocationPropValue
&& string.IsNullOrEmpty(pickupDirectoryLocationPropValue) == false)
{
return true;
}
return false;
}
}
/// <summary>
@@ -141,7 +164,7 @@ namespace Umbraco.Core.Configuration
get
{
return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path)
? Current.IOHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path])
? _ioHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path])
: string.Empty;
}
}
@@ -160,7 +183,7 @@ namespace Umbraco.Core.Configuration
}
set
{
SaveSetting(Constants.AppSettings.ConfigurationStatus, value);
SaveSetting(Constants.AppSettings.ConfigurationStatus, value, _ioHelper);
}
}
@@ -169,9 +192,9 @@ namespace Umbraco.Core.Configuration
/// </summary>
/// <param name="key">Key of the setting to be saved.</param>
/// <param name="value">Value of the setting to be saved.</param>
internal static void SaveSetting(string key, string value)
internal static void SaveSetting(string key, string value, IIOHelper ioHelper)
{
var fileName = Current.IOHelper.MapPath(string.Format("{0}/web.config", Current.IOHelper.Root));
var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
@@ -191,9 +214,9 @@ namespace Umbraco.Core.Configuration
/// Removes a setting from the configuration file.
/// </summary>
/// <param name="key">Key of the setting to be removed.</param>
internal static void RemoveSetting(string key)
public static void RemoveSetting(string key, IIOHelper ioHelper)
{
var fileName = Current.IOHelper.MapPath(string.Format("{0}/web.config", Current.IOHelper.Root));
var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
@@ -207,28 +230,25 @@ namespace Umbraco.Core.Configuration
}
}
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
public static bool DebugMode
public bool DebugMode
{
get
{
try
{
if (HttpContext.Current != null)
if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation)
{
return HttpContext.Current.IsDebuggingEnabled;
var debugElement = compilation.ElementInformation.Properties["debug"];
return debugElement != null && (debugElement.Value is bool debug && debug);
}
//go and get it from config directly
var section = ConfigurationManager.GetSection("system.web/compilation") as CompilationSection;
return section != null && section.Debug;
}
catch
{
return false;
// ignored
}
return false;
}
}
@@ -283,47 +303,6 @@ namespace Umbraco.Core.Configuration
}
}
/// <inheritdoc />
public string LocalTempPath
{
get
{
if (_localTempPath != null)
return _localTempPath;
switch (LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return _localTempPath = System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
case LocalTempStorage.EnvironmentTemp:
// environment temp is unique, we need a folder per site
// use a hash
// combine site name and application id
// site name is a Guid on Cloud
// application id is eg /LM/W3SVC/123456/ROOT
// the combination is unique on one server
// and, if a site moves from worker A to B and then back to A...
// hopefully it gets a new Guid or new application id?
var siteName = HostingEnvironment.SiteName;
var applicationId = HostingEnvironment.ApplicationID; // ie HttpRuntime.AppDomainAppId
var hashString = siteName + "::" + applicationId;
var hash = hashString.GenerateHash();
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
return _localTempPath = siteTemp;
//case LocalTempStorage.Default:
//case LocalTempStorage.Unknown:
default:
return _localTempPath = Current.IOHelper.MapPath("~/App_Data/TEMP");
}
}
}
/// <summary>
/// Gets the default UI language.
@@ -391,6 +370,21 @@ namespace Umbraco.Core.Configuration
private string _umbracoPath = null;
public string UmbracoPath => GetterWithDefaultValue(Constants.AppSettings.UmbracoPath, "~/umbraco", ref _umbracoPath);
private bool _installMissingDatabase;
public bool InstallMissingDatabase => GetterWithDefaultValue("Umbraco.Core.RuntimeState.InstallMissingDatabase", false, ref _installMissingDatabase);
private bool _installEmptyDatabase;
public bool InstallEmptyDatabase => GetterWithDefaultValue("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false, ref _installEmptyDatabase);
private bool _disableElectionForSingleServer;
public bool DisableElectionForSingleServer => GetterWithDefaultValue(Constants.AppSettings.DisableElectionForSingleServer, false, ref _disableElectionForSingleServer);
private string _registerType;
public string RegisterType => GetterWithDefaultValue(Constants.AppSettings.RegisterType, string.Empty, ref _registerType);
private string _databaseFactoryServerVersion;
public string DatabaseFactoryServerVersion => GetterWithDefaultValue(Constants.AppSettings.Debug.DatabaseFactoryServerVersion, string.Empty, ref _databaseFactoryServerVersion);
private T GetterWithDefaultValue<T>(string appSettingKey, T defaultValue, ref T backingField)
{
if (backingField != null) return backingField;

View File

@@ -0,0 +1,10 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Umbraco Cms
[assembly: InternalsVisibleTo("Umbraco.Tests")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")]
// Allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

View File

@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Remove="obj\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="obj\**" />
</ItemGroup>
<ItemGroup>
<None Remove="obj\**" />
</ItemGroup>
<ItemGroup>
<_UnmanagedRegistrationCache Remove="obj\Umbraco.Configuration.csproj.UnmanagedRegistration.cache" />
<_UnmanagedRegistrationCache Remove="obj\Umbraco.Configuration.csproj.UnmanagedRegistration.cache" />
<_UnmanagedRegistrationCache Remove="obj\Umbraco.Configuration.csproj.UnmanagedRegistration.cache" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Abstractions\Umbraco.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Umbraco.Core, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>C:\Users\Bjarke\AppData\Local\Temp\Temporary ASP.NET Files\root\408beac9\de517473\assembly\dl3\77bf709f\48ac59e4_3595d501\Umbraco.Core.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -33,7 +33,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("allowedUploadFiles")]
internal CommaDelimitedConfigurationElement AllowedUploadFiles => GetOptionalDelimitedElement("allowedUploadFiles", new string[0]);
[ConfigurationProperty("showDeprecatedPropertyEditors")]
internal InnerTextConfigurationElement<bool> ShowDeprecatedPropertyEditors => GetOptionalTextElement("showDeprecatedPropertyEditors", false);

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
//set the default
GetDefaultImageFileTypes());
internal static string[] GetDefaultImageFileTypes()
public static string[] GetDefaultImageFileTypes()
{
return new[] {"jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"};
}
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
}
}
internal static ImagingAutoFillPropertiesCollection GetDefaultImageAutoFillProperties()
public static ImagingAutoFillPropertiesCollection GetDefaultImageAutoFillProperties()
{
return new ImagingAutoFillPropertiesCollection
{

View File

@@ -38,7 +38,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
}
}
internal static CharCollection GetDefaultCharReplacements()
public static CharCollection GetDefaultCharReplacements()
{
var dictionary = new Dictionary<char, string>()
{

View File

@@ -2,26 +2,26 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
internal class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
{
[ConfigurationProperty("backOffice")]
internal BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"];
public BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"];
[ConfigurationProperty("content")]
internal ContentElement Content => (ContentElement)this["content"];
public ContentElement Content => (ContentElement)this["content"];
[ConfigurationProperty("security")]
internal SecurityElement Security => (SecurityElement)this["security"];
public SecurityElement Security => (SecurityElement)this["security"];
[ConfigurationProperty("requestHandler")]
internal RequestHandlerElement RequestHandler => (RequestHandlerElement)this["requestHandler"];
public RequestHandlerElement RequestHandler => (RequestHandlerElement)this["requestHandler"];
[ConfigurationProperty("logging")]
internal LoggingElement Logging => (LoggingElement)this["logging"];
public LoggingElement Logging => (LoggingElement)this["logging"];
[ConfigurationProperty("web.routing")]
internal WebRoutingElement WebRouting => (WebRoutingElement)this["web.routing"];
public WebRoutingElement WebRouting => (WebRoutingElement)this["web.routing"];
IContentSection IUmbracoSettingsSection.Content => Content;

View File

@@ -0,0 +1,33 @@
using System.Configuration;
using Semver;
using Umbraco.Core;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public static class UmbracoVersionExtensions
{
/// <summary>
/// Gets the "local" version of the site.
/// </summary>
/// <remarks>
/// <para>Three things have a version, really: the executing code, the database model,
/// and the site/files. The database model version is entirely managed via migrations,
/// and changes during an upgrade. The executing code version changes when new code is
/// deployed. The site/files version changes during an upgrade.</para>
/// </remarks>
public static SemVersion LocalVersion(this IUmbracoVersion umbracoVersion)
{
try
{
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus];
return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
}
catch
{
return null;
}
}
}
}

View File

@@ -61,7 +61,7 @@ namespace Umbraco.Core.Composing
}
}
internal static bool HasFactory => _factory != null;
public static bool HasFactory => _factory != null;
/// <summary>
/// Resets <see cref="Current"/>. Indented for testing only, and not supported in production code.
@@ -93,11 +93,11 @@ namespace Umbraco.Core.Composing
/// <para>Unlocks <see cref="Configs"/> so that it is possible to add configurations
/// directly to <see cref="Current"/> without having to wire composition.</para>
/// </remarks>
public static void UnlockConfigs()
public static void UnlockConfigs(IConfigsFactory configsFactory)
{
if (_factory != null)
throw new InvalidOperationException("Cannot unlock configs when a factory has been set.");
_configs = new Configs();
_configs = configsFactory.Create();
}
internal static event EventHandler Resetted;
@@ -113,7 +113,7 @@ namespace Umbraco.Core.Composing
public static ILogger Logger
=> _logger ?? (_logger = _factory?.TryGetInstance<ILogger>()
?? new DebugDiagnosticsLogger());
?? new DebugDiagnosticsLogger(new MessageTemplates()));
public static IProfiler Profiler
=> _profiler ?? (_profiler = _factory?.TryGetInstance<IProfiler>()
@@ -207,6 +207,9 @@ namespace Umbraco.Core.Composing
public static readonly IIOHelper IOHelper = Umbraco.Core.IO.IOHelper.Default;
public static IUmbracoVersion UmbracoVersion
=> Factory.GetInstance<IUmbracoVersion>();
#endregion
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Configuration;
using System.Reflection;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Composing
{
@@ -21,11 +21,11 @@ namespace Umbraco.Core.Composing
/// To override the default LightInjectContainer, add an appSetting named 'Umbraco.Core.RegisterType' with
/// a fully qualified type name to a class with a static method "Create" returning an IRegister.
/// </remarks>
public static IRegister Create()
public static IRegister Create(IGlobalSettings globalSettings)
{
Type type;
var configuredTypeName = ConfigurationManager.AppSettings[Constants.AppSettings.RegisterType];
var configuredTypeName = globalSettings.RegisterType;
if (configuredTypeName.IsNullOrWhiteSpace())
{
// try to get the web LightInject container type,

View File

@@ -1,5 +1,6 @@
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
@@ -22,7 +23,8 @@ namespace Umbraco.Core
TypeLoader typeLoader,
IRuntimeState state,
ITypeFinder typeFinder,
IIOHelper ioHelper)
IIOHelper ioHelper,
IUmbracoVersion umbracoVersion)
{
composition.RegisterUnique(logger);
composition.RegisterUnique(profiler);
@@ -35,6 +37,7 @@ namespace Umbraco.Core
composition.RegisterUnique(state);
composition.RegisterUnique(typeFinder);
composition.RegisterUnique(ioHelper);
composition.RegisterUnique(umbracoVersion);
}
}
}

View File

@@ -1,51 +1,56 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Routing;
using Umbraco.Core.Composing;
using System.Web.Hosting;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public static class GlobalSettingsExtensions
{
private static string _mvcArea;
private static string _localTempPath;
/// <summary>
/// This returns the string of the MVC Area route.
/// Gets the location of temporary files.
/// </summary>
/// <remarks>
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
///
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
/// </remarks>
public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings)
public static string LocalTempPath(this IGlobalSettings globalSettings, IIOHelper ioHelper)
{
if (_mvcArea != null) return _mvcArea;
_mvcArea = GetUmbracoMvcAreaNoCache(globalSettings);
if (_localTempPath != null)
return _localTempPath;
return _mvcArea;
}
internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings)
{
if (globalSettings.Path.IsNullOrWhiteSpace())
switch (globalSettings.LocalTempStorageLocation)
{
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
case LocalTempStorage.AspNetTemp:
return _localTempPath = System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
case LocalTempStorage.EnvironmentTemp:
// environment temp is unique, we need a folder per site
// use a hash
// combine site name and application id
// site name is a Guid on Cloud
// application id is eg /LM/W3SVC/123456/ROOT
// the combination is unique on one server
// and, if a site moves from worker A to B and then back to A...
// hopefully it gets a new Guid or new application id?
var siteName = HostingEnvironment.SiteName;
var applicationId = HostingEnvironment.ApplicationID; // ie HttpRuntime.AppDomainAppId
var hashString = siteName + "::" + applicationId;
var hash = hashString.GenerateHash();
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
return _localTempPath = siteTemp;
//case LocalTempStorage.Default:
//case LocalTempStorage.Unknown:
default:
return _localTempPath = ioHelper.MapPath("~/App_Data/TEMP");
}
var path = globalSettings.Path;
if (path.StartsWith(Current.IOHelper.Root)) // beware of TrimStart, see U4-2518
path = path.Substring(Current.IOHelper.Root.Length);
return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
}
}

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