Core.Configuration - import infrastructure

This commit is contained in:
Stephan
2013-02-26 16:52:44 -01:00
parent 07bdd138cc
commit 6c4ee40b96
10 changed files with 240 additions and 8 deletions

View File

@@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Configuration;
namespace Umbraco.Core.Configuration
{
/// <summary>
/// A case-insensitive configuration converter for enumerations.
/// </summary>
/// <typeparam name="T">The type of the enumeration.</typeparam>
internal class CaseInsensitiveEnumConfigConverter<T> : ConfigurationConverterBase
where T : struct
{
public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
{
if (data == null)
throw new ArgumentNullException("data");
//return Enum.Parse(typeof(T), (string)data, true);
T value;
if (Enum.TryParse((string)data, true, out value))
return value;
throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.",
data, typeof(T).Name,
string.Join(", ", Enum.GetValues(typeof(T)).Cast<T>())));
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Configuration
{
/// <summary>
/// Indicates the configuration key for a section or a group.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
internal sealed class ConfigurationKeyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationKeyAttribute"/> class with a configuration key.
/// </summary>
/// <param name="configurationKey">The configurationkey.</param>
/// <remarks>The default configuration key type is <c>Umbraco</c>.</remarks>
public ConfigurationKeyAttribute(string configurationKey)
: this(configurationKey, ConfigurationKeyType.Umbraco)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationKeyAttribute"/> class with a configuration key and a key type.
/// </summary>
/// <param name="configurationKey">The configurationkey.</param>
/// <param name="keyType">The key type.</param>
public ConfigurationKeyAttribute(string configurationKey, ConfigurationKeyType keyType)
{
ConfigurationKey = configurationKey;
KeyType = keyType;
}
/// <summary>
/// Gets or sets the configuration key.
/// </summary>
public string ConfigurationKey { get; private set; }
/// <summary>
/// Gets or sets the configuration key type.
/// </summary>
public ConfigurationKeyType KeyType { get; private set; }
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Configuration
{
/// <summary>
/// Indicates the type of configuration section keys.
/// </summary>
internal enum ConfigurationKeyType
{
/// <summary>
/// An Umbraco section ie with path "/umbraco/sectionKey".
/// </summary>
Umbraco,
/// <summary>
/// An Umbraco plugins section ie with path "/umbraco.plugins/sectionKey".
/// </summary>
Plugins,
/// <summary>
/// A raw section ie with path "/sectionKey".
/// </summary>
Raw
}
}

View File

@@ -0,0 +1,33 @@
using System.Configuration;
namespace Umbraco.Core.Configuration
{
// note - still must work on how to support read-only and ResetSection for collections
// note - still must work on how to spread config over files (aka DeepConfig in v5)
/// <summary>
/// Represents an Umbraco section within the configuration file.
/// </summary>
/// <remarks>
/// <para>The requirement for these sections is to be read-only.</para>
/// <para>However for unit tests purposes it is internally possible to override some values, and
/// then calling <c>>ResetSection</c> should cancel these changes and bring the section back to
/// what it was originally.</para>
/// <para>The <c>UmbracoSettings.For{T}</c> method will return a section, either one that
/// is in the configuration file, or a section that was created with default values.</para>
/// </remarks>
internal abstract class UmbracoConfigurationSection : ConfigurationSection
{
/// <summary>
/// Gets a value indicating whether the section actually is in the configuration file.
/// </summary>
protected bool IsPresent { get { return ElementInformation.IsPresent; } }
/// <summary>
/// Resets settings that were set programmatically, to their initial values.
/// </summary>
/// <remarks>>To be used in unit tests.</remarks>
internal protected virtual void ResetSection()
{ }
}
}

View File

@@ -6,9 +6,11 @@ using System.Threading;
using System.Web;
using System.Web.Caching;
using System.Xml;
using System.Configuration;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.Configuration
@@ -52,7 +54,7 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
/// </summary>
internal static void ResetSetters()
private static void ResetSetters()
{
_addTrailingSlash = null;
_forceSafeAliases = null;
@@ -60,7 +62,7 @@ namespace Umbraco.Core.Configuration
_useDomainPrefixes = null;
_umbracoLibraryCacheDuration = null;
_trySkipIisCustomErrors = null;
SettingsFilePath = null;
SettingsFilePath = null;
}
internal const string TempFriendlyXmlChildContainerNodename = ""; // "children";
@@ -1440,6 +1442,95 @@ namespace Umbraco.Core.Configuration
}
#endregion
}
}
}
#region Extensible settings
/// <summary>
/// Resets settings that were set programmatically, to their initial values.
/// </summary>
/// <remarks>To be used in unit tests.</remarks>
internal static void Reset()
{
ResetSetters();
using (new WriteLock(SectionsLock))
{
foreach (var section in Sections.Values)
section.ResetSection();
}
}
private static readonly ReaderWriterLockSlim SectionsLock = new ReaderWriterLockSlim();
private static readonly Dictionary<Type, UmbracoConfigurationSection> Sections = new Dictionary<Type, UmbracoConfigurationSection>();
/// <summary>
/// Gets the specified UmbracoConfigurationSection.
/// </summary>
/// <typeparam name="T">The type of the UmbracoConfigurationSectiont.</typeparam>
/// <returns>The UmbracoConfigurationSection of the specified type.</returns>
internal static T For<T>()
where T : UmbracoConfigurationSection, new()
{
var sectionType = typeof (T);
using (new WriteLock(SectionsLock))
{
if (Sections.ContainsKey(sectionType)) return Sections[sectionType] as T;
var attr = sectionType.GetCustomAttribute<ConfigurationKeyAttribute>(false);
if (attr == null)
throw new InvalidOperationException(string.Format("Type \"{0}\" is missing attribute ConfigurationKeyAttribute.", sectionType.FullName));
var sectionKey = attr.ConfigurationKey;
if (string.IsNullOrWhiteSpace(sectionKey))
throw new InvalidOperationException(string.Format("Type \"{0}\" ConfigurationKeyAttribute value is null or empty.", sectionType.FullName));
var keyType = attr.KeyType;
var section = GetSection(sectionType, sectionKey, keyType);
Sections[sectionType] = section;
return section as T;
}
}
private static UmbracoConfigurationSection GetSection(Type sectionType, string key, ConfigurationKeyType keyType)
{
if (!sectionType.Inherits<UmbracoConfigurationSection>())
throw new ArgumentException(string.Format(
"Type \"{0}\" does not inherit from UmbracoConfigurationSection.", sectionType.FullName), "sectionType");
switch (keyType)
{
case ConfigurationKeyType.Umbraco:
key = "umbraco/" + key;
break;
case ConfigurationKeyType.Plugins:
key = "umbraco.plugins/" + key;
break;
case ConfigurationKeyType.Raw:
break;
default:
throw new ArgumentOutOfRangeException("keyType", keyType, "Invalid ConfigurationKeyType value.");
}
var section = ConfigurationManager.GetSection(key);
if (section != null && section.GetType() != sectionType)
throw new InvalidCastException(string.Format("Section at key \"{0}\" is of type \"{1}\" and not \"{2}\".",
key, section.GetType().FullName, sectionType.FullName));
if (section != null) return section as UmbracoConfigurationSection;
section = Activator.CreateInstance(sectionType) as UmbracoConfigurationSection;
if (section == null)
throw new NullReferenceException(string.Format(
"Activator failed to create an instance of type \"{0}\" for key\"{1}\" and returned null.",
sectionType.FullName, key));
return section as UmbracoConfigurationSection;
}
#endregion
}
}

View File

@@ -112,10 +112,14 @@
<Compile Include="CodeAnnotations\UmbracoWillObsoleteAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
<Compile Include="Configuration\CaseInsensitiveEnumConfigConverter.cs" />
<Compile Include="Configuration\ClientDependencyConfiguration.cs" />
<Compile Include="Configuration\ConfigurationKeyAttribute.cs" />
<Compile Include="Configuration\ConfigurationKeyType.cs" />
<Compile Include="Configuration\FileSystemProviderElement.cs" />
<Compile Include="Configuration\FileSystemProviderElementCollection.cs" />
<Compile Include="Configuration\FileSystemProvidersSection.cs" />
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoVersion.cs" />
<Compile Include="CoreBootManager.cs" />
<Compile Include="DatabaseContext.cs" />

View File

@@ -105,7 +105,7 @@ namespace Umbraco.Tests.ContentStores
[TearDown]
public void TearDown()
{
UmbracoSettings.ResetSetters();
UmbracoSettings.Reset();
}
[Test]

View File

@@ -27,7 +27,7 @@ namespace Umbraco.Tests.TestHelpers
{
//reset settings
SettingsForTests.Reset();
UmbracoSettings.ResetSetters();
TestHelper.CleanContentDirectories();
//reset the app context, this should reset most things that require resetting like ALL resolvers
ApplicationContext.Current.DisposeIfDisposable();

View File

@@ -99,7 +99,7 @@ namespace Umbraco.Tests.TestHelpers
public static void Reset()
{
UmbracoSettings.ResetSetters();
UmbracoSettings.Reset();
GlobalSettings.ResetCache();
foreach (var kvp in SavedAppSettings)
ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value);

View File

@@ -15,7 +15,7 @@ namespace Umbraco.Tests
[TearDown]
public void TearDown()
{
UmbracoSettings.ResetSetters();
UmbracoSettings.Reset();
}
// test normal urls