While I found a ton of tutorials online for how to write it all by hand, nothing automated. Attached are some screenshots of the tool in use :
So once compiled into the target application, the developer can get at the settings by calling the generated method with this signature:
public static MyConfigSection GetSettings()
Here is the whole generated set of classes :
namespace MyApp.NameSpace {
using System.Configuration;
using System;
public class MyConfigSection : System.Configuration.ConfigurationSection {
[System.Configuration.ConfigurationProperty("Teams")]
public virtual TeamCollection Teams {
get {
return ((TeamCollection)(this["Teams"]));
}
}
static MyConfigSection GetSettings() {
return ((MyConfigSection)(System.Configuration.ConfigurationManager.GetSection(MyConfigSection)));
}
}
public class Team : System.Configuration.ConfigurationElement {
[System.Configuration.ConfigurationProperty("Name")]
public virtual string Name {
get {
return ((string)(this["Name"]));
}
}
[System.Configuration.ConfigurationProperty("Players")]
public virtual PlayerCollection Players {
get {
return ((PlayerCollection)(this["Players"]));
}
}
}
public class TeamCollection : System.Configuration.ConfigurationElementCollection {
protected override string ElementName {
get {
return "Team";
}
}
protected override System.Configuration.ConfigurationElement CreateNewElement() {
return new Team();
}
protected override object GetElementKey(System.Configuration.ConfigurationElement element) {
return ((Team)(element)).Name;
}
}
public class Player : System.Configuration.ConfigurationElement {
[System.Configuration.ConfigurationProperty("Name")]
public virtual string Name {
get {
return ((string)(this["Name"]));
}
}
[System.Configuration.ConfigurationProperty("Position")]
public virtual string Position {
get {
return ((string)(this["Position"]));
}
}
}
public class PlayerCollection : System.Configuration.ConfigurationElementCollection {
protected override string ElementName {
get {
return "Player";
}
}
protected override System.Configuration.ConfigurationElement CreateNewElement() {
return new Player();
}
protected override object GetElementKey(System.Configuration.ConfigurationElement element) {
return ((Player)(element)).Name;
}
}
}
Here is the Class where the CodeDom namespace objects create the config classes:
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using Microsoft.CSharp;
using System.IO;
namespace CustomConfigBuilder
{
public static class Shared
{
public const int _elementImageIndex = 1;
public const int _attributeImageIndex = 0;
public const string _rootConfigNodeName = "RootConfigNode";
public static bool HasChildAttributes(TreeNode node)
{
foreach (TreeNode childNode in node.Nodes)
if (childNode.Tag.ToString() == Shared._attributeImageIndex.ToString())
return true;
return false;
}
}
public class configClassBuilder
{
#region "Methods for building classes"
private static void addBaseGetCollectionIndexerFunction(string name, CodeTypeDeclaration parent)
{
CodeMemberProperty propertyIndexer = new CodeMemberProperty();
propertyIndexer.HasGet = true;
propertyIndexer.HasSet = false;
propertyIndexer.Attributes = MemberAttributes.Public;
propertyIndexer.Type = new CodeTypeReference(name);
propertyIndexer.Name = "Item";
propertyIndexer.Parameters.Add(
new CodeParameterDeclarationExpression(
new CodeTypeReference(typeof(int)), "index"));
CodeMethodReferenceExpression baseGet =
new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "BaseGet");
propertyIndexer.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeCastExpression(
new CodeTypeReference(name),
new CodeMethodInvokeExpression(
baseGet,
new CodeSnippetExpression[] { new CodeSnippetExpression("index") }))));
parent.Members.Add(propertyIndexer);
}
private void addConfigurationElementsCollection(CodeNamespace codeNS,
string name,
CodeTypeDeclaration parent,
CodeTypeDeclaration itemInCollection)
{
CodeTypeReference configPropertyReference =
new CodeTypeReference(typeof(ConfigurationProperty));
// For a collection
CodeTypeDeclaration configElements = new CodeTypeDeclaration(name + "Collection");
configElements.BaseTypes.Add(typeof(ConfigurationElementCollection));
codeNS.Types.Add(configElements);
// Make the Collection a property of the Config Section.
CodeMemberProperty property = new CodeMemberProperty();
property.Name = name + "s";
property.Type = new CodeTypeReference(configElements.Name);
property.HasGet = true;
property.HasSet = false;
property.Attributes = MemberAttributes.Public;
CodeAttributeArgument codeAttributeArgument = new CodeAttributeArgument();
codeAttributeArgument.Value = new CodeSnippetExpression("\"" + name + "s\"");
property.CustomAttributes.Add(
new CodeAttributeDeclaration(configPropertyReference,
new CodeAttributeArgument[] { codeAttributeArgument }));
// Add the elements collection to whatever parent section type is.
parent.Members.Add(property);
CodeIndexerExpression indexer =
new CodeIndexerExpression(new CodeThisReferenceExpression(),
new CodeExpression[] { new CodeSnippetExpression("\"" + name + "s\"") });
CodeCastExpression castIndexer =
new CodeCastExpression(new CodeTypeReference(configElements.Name), indexer);
property.GetStatements.Add(new CodeMethodReturnStatement(castIndexer));
addCreateNewElementMethod(name, configElements);
// protected override object GetElementKey(ConfigurationElement element)
CodeMemberMethod methodGetKey = new CodeMemberMethod();
methodGetKey.Attributes = MemberAttributes.Override | MemberAttributes.Family;
methodGetKey.Name = "GetElementKey";
methodGetKey.Parameters.Add(
new CodeParameterDeclarationExpression(
new CodeTypeReference(typeof(ConfigurationElement)), "element"));
methodGetKey.ReturnType = new CodeTypeReference(typeof(object));
CodeCastExpression castReturn =
new CodeCastExpression(new CodeTypeReference(itemInCollection.Name),
new CodeVariableReferenceExpression("element"));
CodePropertyReferenceExpression propertyOfItem =
new CodePropertyReferenceExpression(castReturn,
itemInCollection.Members[0].Name);
methodGetKey.Statements.Add(new CodeMethodReturnStatement(propertyOfItem));
configElements.Members.Add(methodGetKey);
// Add the "this" indexer from the Base Collection.
addBaseGetCollectionIndexerFunction(name, parent);
// Properties of the Collection
addElementNameProperty(name, configElements);
}
private void addFieldsToElement(TreeNode treeNode, CodeTypeDeclaration elementDataType)
{
foreach (TreeNode attribute in treeNode.Nodes)
if (attribute.Tag.ToString() == Shared._attributeImageIndex.ToString())
addAttributeToElement(elementDataType, attribute.Text);
}
private void addImportsToNamespace(CodeNamespace ns)
{
CodeNamespaceImport configNS = new CodeNamespaceImport("System.Configuration");
ns.Imports.Add(configNS);
configNS = new CodeNamespaceImport("System");
ns.Imports.Add(configNS);
}
private void addClientSettingsAccessor(CodeTypeDeclaration settingsType)
{
CodeMemberMethod settingsGetter = new CodeMemberMethod();
settingsGetter.Name = "GetSettings";
settingsGetter.ReturnType = new CodeTypeReference(settingsType.Name);
settingsGetter.Attributes = MemberAttributes.Static | MemberAttributes.Public ;
CodeMethodInvokeExpression invokeGet =
new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(ConfigurationManager)),
"GetSection",
new CodeSnippetExpression[] { new CodeSnippetExpression(settingsType.Name) });
CodeCastExpression castReturn =
new CodeCastExpression(new CodeTypeReference(settingsType.Name), invokeGet);
settingsGetter.Statements.Add(new CodeMethodReturnStatement(castReturn));
settingsType.Members.Add(settingsGetter);
}
private void addAttributeToElement(CodeTypeDeclaration elementType, string name)
{
CodeTypeReference configPropertyReference =
new CodeTypeReference(typeof(ConfigurationProperty));
CodeMemberProperty property = new CodeMemberProperty();
property.Name = name;
property.Type = new CodeTypeReference(typeof(string));
property.HasGet = true;
property.HasSet = false;
property.Attributes = MemberAttributes.Public;
CodeIndexerExpression propertyIndexer =
new CodeIndexerExpression(new CodeThisReferenceExpression(),
new CodeExpression[] { new CodeSnippetExpression("\"" + name + "\"") });
CodeCastExpression castIndexer =
new CodeCastExpression(new CodeTypeReference(typeof(string)), propertyIndexer);
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(castIndexer);
property.GetStatements.Add(returnStatement);
CodeAttributeArgument codeAttributeArgument = new CodeAttributeArgument();
// codeAttributeArgument.Name = "Name";
codeAttributeArgument.Value = new CodeSnippetExpression("\"" + name + "\"");
property.CustomAttributes.Add(
new CodeAttributeDeclaration(configPropertyReference,
new CodeAttributeArgument[] { codeAttributeArgument }));
elementType.Members.Add(property);
}
private void addCreateNewElementMethod(string name, CodeTypeDeclaration configElements)
{
CodeMemberMethod methodCreate = new CodeMemberMethod();
methodCreate.ReturnType = new CodeTypeReference(typeof(ConfigurationElement));
methodCreate.Name = "CreateNewElement";
methodCreate.Attributes = MemberAttributes.Override | MemberAttributes.Family;
methodCreate.Statements.Add(
new CodeMethodReturnStatement(
new CodeObjectCreateExpression(name, new CodeExpression[] { })));
configElements.Members.Add(methodCreate);
}
private static void addElementNameProperty(string name, CodeTypeDeclaration configElements)
{
CodeMemberProperty propEleName = new CodeMemberProperty();
propEleName.Name = "ElementName";
propEleName.Attributes = MemberAttributes.Override | MemberAttributes.Family;
propEleName.HasSet = false;
propEleName.HasGet = true;
propEleName.Type = new CodeTypeReference(typeof(string));
propEleName.GetStatements.Add(new CodeMethodReturnStatement(
new CodeSnippetExpression("\"" + name + "\"")));
configElements.Members.Add(propEleName);
}
private CodeTypeDeclaration addConfigurationElement(CodeNamespace codeNS, string name)
{
// For an item in the collection
CodeTypeDeclaration configElement = new CodeTypeDeclaration(name);
configElement.BaseTypes.Add(typeof(ConfigurationElement));
codeNS.Types.Add(configElement);
return configElement;
}
public string RunBuild(TreeView tvConfigData, string SaveTo)
{
CodeNamespace configgedNamespace = new CodeNamespace("MyApp.NameSpace");
CodeTypeDeclaration configSectionDec = new CodeTypeDeclaration(tvConfigData.Nodes[0].Text);
configSectionDec.IsClass = true;
configSectionDec.BaseTypes.Add(typeof(ConfigurationSection));
configgedNamespace.Types.Add(configSectionDec);
addImportsToNamespace(configgedNamespace);
foreach (TreeNode tn in tvConfigData.Nodes[Shared._rootConfigNodeName].Nodes)
{
CodeTypeDeclaration newElement = addConfigurationElement(configgedNamespace, tn.Text);
// Add Fields to the new configuration element.
addFieldsToElement(tn, newElement);
// Add a collection class to hold all the instances of the element.
addConfigurationElementsCollection(configgedNamespace, tn.Text, configSectionDec, newElement);
addClientSettingsAccessor(configSectionDec);
// Add Any Child Elements to the new configuration element.
foreach (TreeNode childNode in tn.Nodes)
if (childNode.Tag.ToString() == Shared._elementImageIndex.ToString())
{
CodeTypeDeclaration newChildElement =
addConfigurationElement(configgedNamespace, childNode.Text);
addFieldsToElement(childNode, newChildElement);
addConfigurationElementsCollection(configgedNamespace,
childNode.Text,
newElement,
newChildElement);
}
}
CSharpCodeProvider provider = new CSharpCodeProvider();
System.CodeDom.Compiler.CodeGeneratorOptions opts =
new System.CodeDom.Compiler.CodeGeneratorOptions();
if (SaveTo.Length > 0 && !SaveTo.Contains("Save "))
{
StreamWriter sw = new StreamWriter(SaveTo);
opts.BlankLinesBetweenMembers = true;
provider.GenerateCodeFromNamespace(configgedNamespace, sw, opts);
sw.Close();
}
StringBuilder sb = new StringBuilder();
StringWriter strWriter = new StringWriter(sb);
provider.GenerateCodeFromNamespace(configgedNamespace, strWriter, opts);
// txtClassResults.Text = sb.ToString();
strWriter.Close();
return sb.ToString();
}
#endregion
}
}
And here is the declaration of the new configuration Type in the App.Config ;
<configuration>
<configSections>
<section name="MyConfigSection" type="MyApp.NameSpace.MyConfigSection, CustomConfigBuilder" />
</configSections>
<MyConfigSection>
<Teams>
<add Name="Dallas Cowboys">
<Players>
<add Name="Terrell Owens" Position="Wide Receiver" />
</Players>
</add>
</Teams>
</MyConfigSection>
</configuration>
No comments:
Post a Comment