Merge pull request #2187 from umbraco/temp-U4-10118

temp u4 10118
This commit is contained in:
Stephan
2017-09-12 16:05:55 +02:00
committed by GitHub
9 changed files with 141 additions and 21 deletions

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProviderElement : ConfigurationElement
public class FileSystemProviderElement : ConfigurationElement, IFileSystemProviderElement
{
private const string ALIAS_KEY = "alias";
private const string TYPE_KEY = "type";
@@ -38,5 +38,30 @@ namespace Umbraco.Core.Configuration
return ((KeyValueConfigurationCollection)(base[PARAMETERS_KEY]));
}
}
string IFileSystemProviderElement.Alias
{
get { return Alias; }
}
string IFileSystemProviderElement.Type
{
get { return Type; }
}
private IDictionary<string, string> _params;
IDictionary<string, string> IFileSystemProviderElement.Parameters
{
get
{
if (_params != null) return _params;
_params = new Dictionary<string, string>();
foreach (KeyValueConfigurationElement element in Parameters)
{
_params.Add(element.Key, element.Value);
}
return _params;
}
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
[ConfigurationCollection(typeof(FileSystemProviderElement), AddItemName = "Provider")]
public class FileSystemProviderElementCollection : ConfigurationElementCollection
public class FileSystemProviderElementCollection : ConfigurationElementCollection, IEnumerable<IFileSystemProviderElement>
{
protected override ConfigurationElement CreateNewElement()
{
@@ -19,12 +19,25 @@ namespace Umbraco.Core.Configuration
return ((FileSystemProviderElement)(element)).Alias;
}
new public FileSystemProviderElement this[string key]
public new FileSystemProviderElement this[string key]
{
get
{
return (FileSystemProviderElement)BaseGet(key);
}
}
IEnumerator<IFileSystemProviderElement> IEnumerable<IFileSystemProviderElement>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as IFileSystemProviderElement;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProvidersSection : ConfigurationSection
public class FileSystemProvidersSection : ConfigurationSection, IFileSystemProvidersSection
{
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
@@ -14,5 +14,17 @@ namespace Umbraco.Core.Configuration
{
get { return ((FileSystemProviderElementCollection)(base[""])); }
}
private IDictionary<string, IFileSystemProviderElement> _providers;
IDictionary<string, IFileSystemProviderElement> IFileSystemProvidersSection.Providers
{
get
{
if (_providers != null) return _providers;
_providers = Providers.ToDictionary(x => x.Alias, x => x);
return _providers;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProviderElement
{
string Alias { get; }
string Type { get; }
IDictionary<string, string> Parameters { get; }
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProvidersSection
{
IDictionary<string, IFileSystemProviderElement> Providers { get; }
}
}

View File

@@ -11,7 +11,7 @@ namespace Umbraco.Core.IO
{
public class FileSystemProviderManager
{
private readonly FileSystemProvidersSection _config;
private readonly IFileSystemProvidersSection _config;
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
@@ -28,16 +28,45 @@ namespace Umbraco.Core.IO
private ShadowWrapper _mvcViewsFileSystem;
#region Singleton & Constructor
private static readonly FileSystemProviderManager Instance = new FileSystemProviderManager();
private static volatile FileSystemProviderManager _instance;
private static readonly object _instanceLocker = new object();
public static FileSystemProviderManager Current
{
get { return Instance; }
get
{
if (_instance != null) return _instance;
lock (_instanceLocker)
{
return _instance ?? (_instance = new FileSystemProviderManager());
}
}
}
/// <summary>
/// For tests only, allows setting the value of the singleton "Current" property
/// </summary>
/// <param name="instance"></param>
public static void SetCurrent(FileSystemProviderManager instance)
{
lock (_instanceLocker)
{
_instance = instance;
}
}
internal static void ResetCurrent()
{
lock (_instanceLocker)
{
if (_instance != null)
_instance.Reset();
}
}
// for tests only, totally unsafe
internal void Reset()
private void Reset()
{
_wrappers.Clear();
_providerLookup.Clear();
@@ -52,10 +81,24 @@ namespace Umbraco.Core.IO
// beware: means that we capture the "current" scope provider - take care in tests!
get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; }
}
internal FileSystemProviderManager()
/// <summary>
/// Constructor that can be used for tests
/// </summary>
/// <param name="configSection"></param>
public FileSystemProviderManager(IFileSystemProvidersSection configSection)
{
_config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
if (configSection == null) throw new ArgumentNullException("configSection");
_config = configSection;
CreateWellKnownFileSystems();
}
/// <summary>
/// Default constructor that will read the config from the locally found config section
/// </summary>
public FileSystemProviderManager()
{
_config = (FileSystemProvidersSection)ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
CreateWellKnownFileSystems();
}
@@ -150,8 +193,9 @@ namespace Umbraco.Core.IO
private ProviderConstructionInfo GetUnderlyingFileSystemCtor(string alias, Func<IFileSystem> fallback)
{
// get config
var providerConfig = _config.Providers[alias];
if (providerConfig == null)
IFileSystemProviderElement providerConfig;
if (_config.Providers.TryGetValue(alias, out providerConfig) == false)
{
if (fallback != null) return null;
throw new ArgumentException(string.Format("No provider found with alias {0}.", alias));
@@ -166,17 +210,21 @@ namespace Umbraco.Core.IO
if (providerType.IsAssignableFrom(typeof(IFileSystem)))
throw new InvalidOperationException(string.Format("Type {0} does not implement IFileSystem.", providerType.FullName));
// find a ctor matching the config parameters
// find a ctor matching the config parameters
var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
var constructor = providerType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.Keys.Contains(y.Name)));
if (constructor == null)
throw new InvalidOperationException(string.Format("Type {0} has no ctor matching the {1} configuration parameter(s).", providerType.FullName, paramCount));
var parameters = new object[paramCount];
if (providerConfig.Parameters != null) // keeps ReSharper happy
if (providerConfig.Parameters != null)
{
var allKeys = providerConfig.Parameters.Keys.ToArray();
for (var i = 0; i < paramCount; i++)
parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
parameters[i] = providerConfig.Parameters[allKeys[i]];
}
return new ProviderConstructionInfo
{

View File

@@ -241,6 +241,8 @@
<Compile Include="Configuration\Grid\IGridConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorsConfig.cs" />
<Compile Include="Configuration\IFileSystemProviderElement.cs" />
<Compile Include="Configuration\IFileSystemProvidersSection.cs" />
<Compile Include="Configuration\UmbracoConfig.cs" />
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoSettings\AppCodeFileExtensionsCollection.cs" />

View File

@@ -26,14 +26,14 @@ namespace Umbraco.Tests.IO
// start clean
// because some tests will create corrupt or weird filesystems
FileSystemProviderManager.Current.Reset();
FileSystemProviderManager.ResetCurrent();
}
[TearDown]
public void TearDown()
{
// stay clean (see note in SetUp)
FileSystemProviderManager.Current.Reset();
FileSystemProviderManager.ResetCurrent();
}
[Test]

View File

@@ -155,7 +155,7 @@ namespace Umbraco.Tests.TestHelpers
// FileSystemProviderManager captures the current ApplicationContext ScopeProvider
// in its current static instance (yea...) so we need to reset it here to ensure
// it is using the proper ScopeProvider
FileSystemProviderManager.Current.Reset();
FileSystemProviderManager.ResetCurrent();
}
protected virtual ApplicationContext CreateApplicationContext()