Skip to content

Commit

Permalink
Merge pull request #112 from TheTribe/release/3.10-beta.3
Browse files Browse the repository at this point in the history
release 3.10-beta.3
  • Loading branch information
TheTribe committed Sep 14, 2013
2 parents d6e39d3 + 4a79888 commit c3cd70a
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 164 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

The following log details the outward-facing changes made to code-patterns since its first migration to GitHub.

## 3.10-beta.3 ##

- Extracted `Patterns.Configuration.InMemoryConfigurationSource` from `Patterns.Testing.Configuration.TestConfigurationSource` ([issue 110](https://github.com/TheTribe/code-patterns/issues/110))

## 3.10-beta.2 ##

- Changes made to `Patterns.Runtime.IDateTimeInfo` and `Patterns.Runtime.DefaultDateTimeInfo` ([issue 105](https://github.com/TheTribe/code-patterns/issues/105)):
Expand Down
163 changes: 2 additions & 161 deletions src/Patterns.Testing/Configuration/TestConfigurationSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,184 +19,25 @@

#endregion

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

using Patterns.Configuration;
using Patterns.Text.RegularExpressions;

namespace Patterns.Testing.Configuration
{
/// <summary>
/// Provides a configuration source that uses an in-memory configuration rather than a
/// file-based one.
/// </summary>
public class TestConfigurationSource : IConfigurationSource
public class TestConfigurationSource : InMemoryConfigurationSource
{
private readonly XContainer _configXml;
private readonly CompiledRegex _sectionNamePattern = "[^/]+$";

/// <summary>
/// Initializes a new instance of the <see cref="TestConfigurationSource" /> class.
/// </summary>
/// <param name="configXml">The config XML.</param>
public TestConfigurationSource(XContainer configXml)
{
_configXml = configXml;
var appSettings = GetSection<AppSettingsSection>("appSettings");
if (appSettings != null)
{
AppSettings = appSettings.Settings.AllKeys
.ToDictionary(key => key, key => appSettings.Settings[key].Value);
}
var connectionStrings = GetSection<ConnectionStringsSection>("connectionStrings");
if (connectionStrings != null)
{
ConnectionStrings = connectionStrings.ConnectionStrings.OfType<ConnectionStringSettings>()
.ToDictionary(settings => settings.Name, settings => settings);
}
}

/// <summary>
/// Gets the app settings.
/// </summary>
/// <value>
/// The app settings.
/// </value>
public IDictionary<string, string> AppSettings { get; private set; }

/// <summary>
/// Gets the connection strings.
/// </summary>
/// <value>
/// The connection strings.
/// </value>
public IDictionary<string, ConnectionStringSettings> ConnectionStrings { get; private set; }

/// <summary>
/// Gets the section.
/// </summary>
/// <param name="sectionName">Name of the section.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public ConfigurationSection GetSection(string sectionName)
{
return DeserializeSection(_configXml, sectionName);
}

/// <summary>
/// Gets the section.
/// </summary>
/// <typeparam name="TSection">The type of the section.</typeparam>
/// <param name="sectionName">Name of the section.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public TSection GetSection<TSection>(string sectionName) where TSection : ConfigurationSection, new()
{
return DeserializeSection<TSection>(_configXml, sectionName);
}

/// <summary>
/// Opens the exe configuration.
/// </summary>
/// <param name="exePath">The exe path.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public IConfiguration OpenExeConfiguration(string exePath)
{
throw new NotSupportedException();
}

/// <summary>
/// Opens the machine configuration.
/// </summary>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public IConfiguration OpenMachineConfiguration()
{
throw new NotSupportedException();
}

/// <summary>
/// Refreshes the section.
/// </summary>
/// <param name="sectionName">Name of the section.</param>
/// <exception cref="System.NotImplementedException"></exception>
public void RefreshSection(string sectionName) {}

/// <summary>
/// Opens the mapped exe configuration.
/// </summary>
/// <param name="fileMap">The file map.</param>
/// <param name="userLevel">The user level.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public IConfiguration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
{
throw new NotSupportedException();
}

/// <summary>
/// Opens the exe configuration.
/// </summary>
/// <param name="userLevel">The user level.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public IConfiguration OpenExeConfiguration(ConfigurationUserLevel userLevel)
{
throw new NotSupportedException();
}

private ConfigurationSection DeserializeSection(XContainer xml, string name)
{
XElement sectionDefinition = xml.Element("configSections")
.Descendants("section")
.FirstOrDefault(section => section.Attribute("name").Value == _sectionNamePattern.Match(name).Value);

if (sectionDefinition == null) return null;

Type sectionType = Type.GetType(sectionDefinition.Attribute("type").Value, false);

if (sectionType == null) return null;

const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
MethodInfo genericFlavor = typeof (TestConfigurationSource).GetMethods(flags)
.FirstOrDefault(method => method.Name == "DeserializeSection" && method.IsGenericMethod);

MethodInfo typedGenericFlavor = genericFlavor.MakeGenericMethod(sectionType);

try
{
return (ConfigurationSection) typedGenericFlavor.Invoke(null, new object[] {xml, name});
}
catch (TargetInvocationException error)
{
throw error.InnerException;
}
}

private static TSection DeserializeSection<TSection>(XContainer xml, string name) where TSection : ConfigurationSection, new()
{
var config = new TSection();
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo deserializer = typeof (TSection).GetMethod("DeserializeSection", flags);
var sectionXml = name.Split('/').Aggregate(xml, (current, part) => current.Element(part));
if (sectionXml == null) return null;

try
{
deserializer.Invoke(config, new object[] {sectionXml.CreateReader()});
}
catch (TargetInvocationException error)
{
throw error.InnerException;
}

return config;
SetConfigurationXml(configXml);
}
}
}
190 changes: 190 additions & 0 deletions src/Patterns/Configuration/InMemoryConfigurationSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

using Patterns.Text.RegularExpressions;

namespace Patterns.Configuration
{
/// <summary>
/// Provides a configuration source that uses an in-memory configuration rather than a
/// file-based one.
/// </summary>
public abstract class InMemoryConfigurationSource : IConfigurationSource
{
protected const string AppSettingsSectionName = "appSettings";
protected const string ConnectionStringsSectionName = "connectionStrings";
protected const string ConfigSectionsElementName = "configSections";
protected const string SectionElementName = "section";
protected const string NameAttributeName = "name";
protected const string TypeAttributeName = "type";
protected const string DeserializeSectionMethodName = "DeserializeSection";
protected const char PathSeparator = '/';
protected readonly CompiledRegex SectionNamePattern = "[^/]+$";
private XContainer _configXml;

/// <summary>
/// Gets the app settings.
/// </summary>
/// <value>
/// The app settings.
/// </value>
public virtual IDictionary<string, string> AppSettings { get; private set; }

/// <summary>
/// Gets the connection strings.
/// </summary>
/// <value>
/// The connection strings.
/// </value>
public virtual IDictionary<string, ConnectionStringSettings> ConnectionStrings { get; private set; }

/// <summary>
/// Gets the section.
/// </summary>
/// <param name="sectionName">Name of the section.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual ConfigurationSection GetSection(string sectionName)
{
return DeserializeSection(_configXml, sectionName);
}

/// <summary>
/// Gets the section.
/// </summary>
/// <typeparam name="TSection">The type of the section.</typeparam>
/// <param name="sectionName">Name of the section.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual TSection GetSection<TSection>(string sectionName) where TSection : ConfigurationSection, new()
{
return DeserializeSection<TSection>(_configXml, sectionName);
}

/// <summary>
/// Opens the exe configuration.
/// </summary>
/// <param name="exePath">The exe path.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual IConfiguration OpenExeConfiguration(string exePath)
{
throw new NotSupportedException();
}

/// <summary>
/// Opens the machine configuration.
/// </summary>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual IConfiguration OpenMachineConfiguration()
{
throw new NotSupportedException();
}

/// <summary>
/// Refreshes the section.
/// </summary>
/// <param name="sectionName">Name of the section.</param>
/// <exception cref="System.NotImplementedException"></exception>
public virtual void RefreshSection(string sectionName) {}

/// <summary>
/// Opens the mapped exe configuration.
/// </summary>
/// <param name="fileMap">The file map.</param>
/// <param name="userLevel">The user level.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual IConfiguration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap,
ConfigurationUserLevel userLevel)
{
throw new NotSupportedException();
}

/// <summary>
/// Opens the exe configuration.
/// </summary>
/// <param name="userLevel">The user level.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
public virtual IConfiguration OpenExeConfiguration(ConfigurationUserLevel userLevel)
{
throw new NotSupportedException();
}

protected void SetConfigurationXml(XContainer configXml)
{
_configXml = configXml;
var appSettings = GetSection<AppSettingsSection>(AppSettingsSectionName);
if (appSettings != null)
{
AppSettings = appSettings.Settings.AllKeys
.ToDictionary(key => key, key => appSettings.Settings[key].Value);
}
var connectionStrings = GetSection<ConnectionStringsSection>(ConnectionStringsSectionName);
if (connectionStrings != null)
{
ConnectionStrings = connectionStrings.ConnectionStrings.OfType<ConnectionStringSettings>()
.ToDictionary(settings => settings.Name, settings => settings);
}
}

protected virtual ConfigurationSection DeserializeSection(XContainer xml, string name)
{
XElement sections = xml.Element(ConfigSectionsElementName);
if (sections == null) return null;

XElement sectionDefinition = sections
.Descendants(SectionElementName)
.FirstOrDefault(section => section.Attribute(NameAttributeName).Value == SectionNamePattern.Match(name).Value);

if (sectionDefinition == null) return null;

Type sectionType = Type.GetType(sectionDefinition.Attribute(TypeAttributeName).Value, false);

if (sectionType == null) return null;

const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
MethodInfo genericFlavor = typeof (InMemoryConfigurationSource).GetMethods(flags)
.FirstOrDefault(method => method.Name == DeserializeSectionMethodName && method.IsGenericMethod);
if (genericFlavor == null) return null;

MethodInfo typedGenericFlavor = genericFlavor.MakeGenericMethod(sectionType);

try
{
return (ConfigurationSection) typedGenericFlavor.Invoke(null, new object[] {xml, name});
}
catch (TargetInvocationException error)
{
throw error.InnerException;
}
}

protected static TSection DeserializeSection<TSection>(XContainer xml, string name)
where TSection : ConfigurationSection, new()
{
var config = new TSection();
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo deserializer = typeof (TSection).GetMethod(DeserializeSectionMethodName, flags);
XContainer sectionXml = name.Split(PathSeparator).Aggregate(xml, (current, part) => current.Element(part));
if (sectionXml == null) return null;

try
{
deserializer.Invoke(config, new object[] {sectionXml.CreateReader()});
}
catch (TargetInvocationException error)
{
throw error.InnerException;
}

return config;
}
}
}
1 change: 1 addition & 0 deletions src/Patterns/Patterns.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<Compile Include="Configuration\IConfiguration.cs" />
<Compile Include="Configuration\IConfigurationManager.cs" />
<Compile Include="Configuration\IConfigurationSource.cs" />
<Compile Include="Configuration\InMemoryConfigurationSource.cs" />
<Compile Include="ExceptionHandling\ExceptionState.cs" />
<Compile Include="ExceptionHandling\Try.cs" />
<Compile Include="Interception\DelegateInterceptor.cs" />
Expand Down
Loading

0 comments on commit c3cd70a

Please sign in to comment.