I'm trying to make DataContract Serializer work with one of my class.
Here it is :
public class MyOwnObservableCollection<T> : ObservableCollection<T>, IDisposable
where T : IObjectWithChangeTracker, INotifyPropertyChanged
{
protected List<T> removedItems;
[DataMember]
public List<T> RemovedItems
{
get { return this.removedItems;}
set { this.removedItems = value;}
}
// Other code removed for simplification
// ...
//
}
It is important to understand that the RemovedItems list gets populated automatically when you remove an Item from the ObservableCollection.
Now serializing an instance of this class using the DataContractSerializer with one element in the removedItems list with the following code :
MyOwnObservableCollection<Test> _Test = new MyOwnObservableCollection<Test>();
DataContractSerializer dcs = new DataContractSerializer(typeof(MyOwnObservableCollection<Test>));
XmlWriterSettings settings = new XmlWriterSettings() { Indent = true };
string fileName = #"Test.xml";
Insurance atest = new Test();
atest.Name = #"sfdsfsdfsff";
_Test.Add(atest);
_Test.RemoveAt(0); // The Iitem in the ObservableCollection is moved to the RemovedItems List/
using (var w = XmlWriter.Create(fileName, settings))
{
dcs.WriteObject(w, _Test);
}
ends with nothing in the XML file :
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfTest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyNameSpace" />
Why is this public property ignored ? What have I missed here ?
TIA.
The problem here is that your class is derived from a collection, and as such, the DataContractSerializer serializes only its items, but not any extra properties, as stated here: No properties when using CollectionDataContract.
A workaround would be using the original (inherited) collection as a property, rather than inheriting from it:
public class MyOwnObservableCollection<T> : IDisposable
where T : IObjectWithChangeTracker, INotifyPropertyChanged
{
readonly ObservableCollection<T> originalCollection = new ObservableCollection<T>();
protected List<T> removedItems = = new List<T>();
[DataMember]
public List<T> RemovedItems
{
get { return this.removedItems;}
set { this.removedItems = value;}
}
[DataMember]
public ObservableCollection<T> OriginalCollection
{
get { return this.originalCollection; }
}
// ...
}
Related
With a simple class/interface like this
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
How can I get the JSON string with only the "Name" property (only the properties of the underlying interface) ?
Actually, when i make that :
var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
I get the full object as JSON (Id + Name);
The method I use,
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _InterfaceType;
public InterfaceContractResolver (Type InterfaceType)
{
_InterfaceType = InterfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
return properties;
}
}
// To serialize do this:
var settings = new JsonSerializerSettings() {
ContractResolver = new InterfaceContractResolver (typeof(IThing))
};
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Improved version with nested interfaces + support for xsd.exe objects
Yet another variation here. The code came from http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html with the following improvements over other answers here
Handles hierarchy, so if you have an Interface2[] within an Interface1 then it will get serialized.
I was trying to serialize a WCF proxy object and the resultant JSON came up as {}. Turned out all properties were set to Ignore=true so I had to add a loop to set them all to not being ignored.
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type[] _interfaceTypes;
private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
public InterfaceContractResolver(params Type[] interfaceTypes)
{
_interfaceTypes = interfaceTypes;
_typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization)
{
var typeToSerialize = _typeToSerializeMap.GetOrAdd(
type,
t => _interfaceTypes.FirstOrDefault(
it => it.IsAssignableFrom(t)) ?? t);
var props = base.CreateProperties(typeToSerialize, memberSerialization);
// mark all props as not ignored
foreach (var prop in props)
{
prop.Ignored = false;
}
return props;
}
}
Inspired by #user3161686, here's a small modification to InterfaceContractResolver:
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
}
You can use conditional serialization. Take a look at this link. Basicly, you need to implement the IContractResolver interface, overload the ShouldSerialize method and pass your resolver to the constructor of the Json Serializer.
An alternative to [JsonIgnore] are the [DataContract] and [DataMember] attributes. If you class is tagged with [DataContract] the serializer will only process properties tagged with the [DataMember] attribute (JsonIgnore is an "opt-out" model while DataContract is "op-in").
[DataContract]
public class Thing : IThing
{
[DataMember]
public int Id { get; set; }
public string Name { get; set; }
}
The limitation of both approaches is that they must be implemented in the class, you cannot add them to the interface definition.
You can add the [JsonIgnore] annotation to ignore an attribute.
I'd like to share what we ended up doing when confronted with this task. Given the OP's interface and class...
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
...we created a class that is the direct implementation of the interface...
public class DirectThing : IThing
{
public string Name { get; set; }
}
Then simply serialized our Thing instance, deserialized it as a DirectThing, then Serialized it as a DirectThing:
var thing = new Thing();
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject<DirectThing>(JsonConvert.SerializeObject(thing)));
This approach can work with a long interface inheritance chain...you just need to make a direct class (DirectThing in this example) at the level of interest. No need to worry about reflection or attributes.
From a maintenance perspective, the DirectThing class is easy to maintain if you add members to IThing because the compiler will give errors if you haven't also put them in DirectThing. However, if you remove a member X from IThing and put it in Thing instead, then you'll have to remember to remove it from DirectThing or else X would be in the end result.
From a performance perspective there are three (de)serialization operations happening here instead of one, so depending on your situation you might like to evaluate the performance difference of reflector/attribute-based solutions versus this solution. In my case I was just doing this on a small scale, so I wasn't concerned about potential losses of some micro/milliseconds.
Hope that helps someone!
in addition to the answer given by #monrow you can use the default [DataContract] and [DataMember]
have a look at this
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
Finally I got when it will not work...
If you want to have inside another complex object it will not be properly serialized.
So I have made version which will extract only data stored in specific assembly and for types which have the same base interface.
So it is made as .Net Core JsonContractResolver.
In addition to data extraction it solves:
a) camelCase conversion before sending data to client
b) uses top most interface from allowed scope (by assembly)
c) fixes order of fields: field from most base class will be listed first and nested object will meet this rule as well.
public class OutputJsonResolver : DefaultContractResolver
{
#region Static Members
private static readonly object syncTargets = new object();
private static readonly Dictionary<Type, IList<JsonProperty>> Targets = new Dictionary<Type, IList<JsonProperty>>();
private static readonly Assembly CommonAssembly = typeof(ICommon).Assembly;
#endregion
#region Override Members
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
if (type.Assembly != OutputJsonResolver.CommonAssembly)
return base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties;
if (OutputJsonResolver.Targets.TryGetValue(type, out properties) == false)
{
lock (OutputJsonResolver.syncTargets)
{
if (OutputJsonResolver.Targets.ContainsKey(type) == false)
{
properties = this.CreateCustomProperties(type, memberSerialization);
OutputJsonResolver.Targets[type] = properties;
}
}
}
return properties;
}
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToCase(Casing.Camel);
}
#endregion
#region Assistants
private IList<JsonProperty> CreateCustomProperties(Type type, MemberSerialization memberSerialization)
{
// Hierarchy
IReadOnlyList<Type> types = this.GetTypes(type);
// Head
Type head = types.OrderByDescending(item => item.GetInterfaces().Length).FirstOrDefault();
// Sources
IList<JsonProperty> sources = base.CreateProperties(head, memberSerialization);
// Targets
IList<JsonProperty> targets = new List<JsonProperty>(sources.Count);
// Repository
IReadOnlyDistribution<Type, JsonProperty> repository = sources.ToDistribution(item => item.DeclaringType);
foreach (Type current in types.Reverse())
{
IReadOnlyPage<JsonProperty> page;
if (repository.TryGetValue(current, out page) == true)
targets.AddRange(page);
}
return targets;
}
private IReadOnlyList<Type> GetTypes(Type type)
{
List<Type> types = new List<Type>();
if (type.IsInterface == true)
types.Add(type);
types.AddRange(type.GetInterfaces());
return types;
}
#endregion
}
I have below data structure to represent the tree
public class TreeNode : IEnumerable<TreeNode>
{
private readonly Dictionary<string, TreeNode> _children =
new Dictionary<string, TreeNode>();
public readonly string ID;
public TreeNode Parent { get; private set; }
public TreeNode()
{
this.ID = Guid.NewGuid().ToString();
}
public void AddChild(TreeNode tNode)
{
if (tNode.Parent != null)
{
tNode.Parent._children.Remove(tNode.ID);
}
tNode.Parent = this;
this._children.Add(tNode.ID, tNode);
}
public IEnumerator<TreeNode> GetEnumerator()
{
return this._children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
I am trying to return this tree structure from wcf service.
[OperationContract]
TreeNode GetMenuItems();
and i get exception saying "Type 'TreeNode' is a recursive collection data contract which is not supported. Consider modifying the definition of collection 'TreeNode' to remove references to itself."
When i annotated the TreeNode calss with [DataContract(IsReference = true)], exception went away.
But when the treenode is received in the client side its children _children property is not coming populated and its always null.
Thanks,
Mallikarjun
By annotating _children with DataMember issue got resolved.
I'm trying to instance an object(s) from xaml. The object's class inherits from a base class. Everything works good except that the a base class property ("Key") is not setting correctly from xaml. It's always null. The object's properties itself are set OK from xaml. Also when I set the Key property from code it sets fine.
I put a breakpoint on the closing bracket of the MainWindow method to view the object data. The hover details tells me the Key property is always null.
Any ideas what I'm doing wrong?
<?xml version="1.0" encoding="utf-8" ?>
<GroupUiItem xmlns="clr-namespace:Configurator.UiCore"
Key="key_grp1" UserName="grp1">
<ParameterUiItem Key="key_par1" UserName="par1"/>
<GroupUiItem Key="key_grp2" UserName="grp2">
<ParameterUiItem Key="key_par2" UserName="par2"/>
<ParameterUiItem Key="key_par3" UserName="par3"/>
</GroupUiItem>
<ParameterUiItem Key="key_par4" UserName="par4"/>
<ParameterUiItem Key="key_par5" UserName="par5"/>
<ParameterUiItem Key="key_par6" UserName="par6"/>
</GroupUiItem>
public partial class MainWindow : Window
{
public MainWindow()
{
GroupUiItem ConfigUi = new GroupUiItem();
InitializeComponent();
using (FileStream stream = new FileStream("XMLFile1.xaml", FileMode.Open, FileAccess.Read))
{
ConfigUi = XamlReader.Load(stream) as GroupUiItem;
}
ConfigUi.Key = "key_grp1"; // this works OK
CategoryList.ItemsSource = ConfigUi.Children;
}
}
// These are in the Configurator.UiCore namespace:
public class ConfiguratorUiItem
{
protected string _Key;
public string Key
{
get { return _Key; }
set { _Key = value; }
}
}
[ContentProperty("Children")]
public class GroupUiItem : ConfiguratorUiItem
{
private ObservableCollection<ConfiguratorUiItem> _Children = new ObservableCollection<ConfiguratorUiItem>();
public ObservableCollection<ConfiguratorUiItem> Children
{ get { return _Children; }
set { _Children = value; }
}
private string _UserName;
public string UserName
{ get { return _UserName; }
set { _UserName = value; }
}
}
public class ParameterUiItem : ConfiguratorUiItem
{
private string _ParameterType;
public string ParameterType
{
get { return _ParameterType; }
set { _ParameterType = value; }
}
private string _UserName;
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
}
OK figured out my problem. Noob mistake. Needed to set build action to None and copy always. I had build action set to a page so it wasn't a loose xaml and wasn't updating to appropriate folder. I copied the xaml file to output directory manually when I first couldn't figure out the problem. This caused the program to always use the old file.
When I did this also had to add ";assembly=Configurator" to the end of the xmlns so that it now reads: "xmlns="clr-namespace:Configurator.UiCore;assembly=Configurator". Then it worked.
I am trying to use Ninject to implement cascading injection into a class that contains an IList field. It seems that, unless I specifically specify each binding to use in the kernel.Get method, the IList property is always injected with a list of a single default object.
The following VSTest code illustrates the problem. The first test fails because the IList field contains one MyType object with Name=null. The second test passes, but I had to specifically tell Ninject what constructor arguments to use. I am using the latest build from the ninject.web.mvc project for MVC 3.
Does Ninject specifically treat IList different, or is there a better way to handle this? Note that this seems to only be a problem when using an IList. Createing a custom collection object that wraps IList works as expected in the first test.
[TestClass()]
public class NinjectTest
{
[TestMethod()]
public void ListTest_Fails_NameNullAndCountIncorrect()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>();
var actual = target.GetList();
// Fails. Returned value is set to a list of a single object equal to default(MyType)
Assert.AreEqual(2, actual.Count());
// Fails because MyType object is initialized with a null "Name" property
Assert.AreEqual("Fred", actual.First().Name);
}
[TestMethod()]
public void ListTest_Passes_SeemsLikeUnnecessaryConfiguration()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>(new ConstructorArgument("myGenericObject", kernel.Get<IGenericObject<MyType>>(new ConstructorArgument("myList", kernel.Get<IList<MyType>>()))));
var actual = target.GetList();
Assert.AreEqual(2, actual.Count());
Assert.AreEqual("Fred", actual.First().Name);
}
}
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IList<MyType>>().ToConstant(new List<MyType> { new MyType { Name = "Fred" }, new MyType { Name = "Bob" } });
Bind<IGenericObject<MyType>>().To<StubObject<MyType>>();
}
}
public class MyModel
{
private IGenericObject<MyType> myGenericObject;
public MyModel(IGenericObject<MyType> myGenericObject)
{
this.myGenericObject = myGenericObject;
}
public IEnumerable<MyType> GetList()
{
return myGenericObject.GetList();
}
}
public interface IGenericObject<T>
{
IList<T> GetList();
}
public class StubObject<T> : IGenericObject<T>
{
private IList<T> _myList;
public StubObject(IList<T> myList)
{
_myList = myList;
}
public IList<T> GetList()
{
return _myList;
}
}
public class MyType
{
public String Name { get; set; }
}
lists, collections and arrays are handled slightly different. For those types ninject will inject a list or array containing an instance of all bindings for the generic type. In your case the implementation type is a class which is aoutobound by default. So the list will contain one instance of that class. If you add an interface to that class and use this one the list will be empty.
I am trying to access settings in my config file, which is a series of xml elements listed as such:
<databases>
<database name="DatabaseOne" Value="[value]" />
<database name="DatabaseTwo" Value="[value]" />
</databases>
Now I want to access it. I have set up classes like so:
Public Class DatabaseConfigurationHandler
Inherits ConfigurationSection
<ConfigurationProperty("Databases", IsDefaultCollection:=True)> _
Public ReadOnly Property Databases() As DatabaseCollection
Get
Return CType(Me("Databases"), DatabaseCollection)
End Get
End Property
End Class
Public Class DatabaseCollection
Inherits ConfigurationElementCollection
Protected Overloads Overrides Function CreateNewElement() As ConfigurationElement
Return (New Database())
End Function
Protected Overloads Overrides Function GetElementKey(ByVal element As ConfigurationElement) As Object
Return (CType(element, Database).DatabaseName)
End Function
End Class
Public Class Database
Inherits ConfigurationElement
<ConfigurationProperty("name", IsKey:=True, IsRequired:=True)> _
Public Property DatabaseName() As String
Get
Return Me("name").ToString()
End Get
Set(ByVal Value As String)
Me("name") = Value
End Set
End Property
<ConfigurationProperty("value", IsRequired:=True)> _
Public Property DatabaseValue() As String
Get
Return Me("value").ToString()
End Get
Set(ByVal Value As String)
Me("value") = Value
End Set
End Property
End Class
I want to be able get the element by it's name and return the value but I can't see to do that:
Dim config As New DatabaseConfigurationHandler
config = System.Configuration.ConfigurationManager.GetSection("databases/database")
Return config.Databases("DatabaseOne")
Am I missing some code, what am I doing wrong? Any other errors in the above?
Thanks.
Here's a cut and paste from something very similar I did a few days ago.
Config:
<ListConfigurations>
<lists>
<add Name="blah" EndpointConfigurationName="blah" ListName="blah" ConnectionString="blah" TableName="blah" FieldsCsv="blah" DbFieldsCsv="blah"/>
<add Name="blah2" EndpointConfigurationName="blah" ListName="blah" ConnectionString="blah" TableName="blah" FieldsCsv="blah" DbFieldsCsv="blah"/>
</lists>
</ListConfigurations>
Config section C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
namespace App
{
/// <summary>
/// Individual list configuration
/// </summary>
class ListConfiguration : ConfigurationElement
{
[ConfigurationProperty("Name", IsKey = true, IsRequired = true)]
public string Name
{
get { return (string)this["Name"]; }
}
[ConfigurationProperty("EndpointConfigurationName", IsRequired = true)]
public string EndpointConfigurationName
{
get { return (string)this["EndpointConfigurationName"]; }
}
[ConfigurationProperty("ListName", IsRequired = true)]
public string ListName
{
get { return (string)this["ListName"]; }
}
[ConfigurationProperty("ConnectionString", IsRequired = true)]
public string ConnectionString
{
get { return (string)this["ConnectionString"]; }
}
[ConfigurationProperty("TableName", IsRequired = true)]
public string TableName
{
get { return (string)this["TableName"]; }
}
[ConfigurationProperty("FieldsCsv", IsRequired = true)]
public string FieldsCsv
{
get { return (string)this["FieldsCsv"]; }
}
[ConfigurationProperty("DbFieldsCsv", IsRequired = true)]
public string DbFieldsCsv
{
get { return (string)this["DbFieldsCsv"]; }
}
}
/// <summary>
/// Collection of list configs
/// </summary>
class ListConfigurationCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new ListConfiguration();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((ListConfiguration)element).Name;
}
}
/// <summary>
/// Config section
/// </summary>
class ListConfigurationSection : ConfigurationSection
{
[ConfigurationProperty("lists")]
public ListConfigurationCollection Lists
{
get { return (ListConfigurationCollection)this["lists"]; }
}
}
}
And the code to pick it up from the main app:
ListConfigurationSection configSection = null;
try
{
configSection = ConfigurationManager.GetSection("ListConfigurations") as ListConfigurationSection;
}
catch (System.Configuration.ConfigurationErrorsException)
{
}
There isn't any good reason to design this kind of stuff by hand anymore. Rather, you should be using the Configuration Section Designer on CodePlex:
http://csd.codeplex.com/
Once installed, you can just add a new item to your project (a configuration section designer) and then add the elements and the constraints. I've found it VERY easy to use, and I will probably never write a piece of code for configuration files again.
You can use this configuration handler instead.. It will work for ALL custom configuration sections
public class XmlConfigurator : IConfigurationSectionHandler
{
public object Create(object parent,
object configContext, XmlNode section)
{
if (section == null)
throw new ArgumentNullException("section",
"Invalid or missing configuration section " +
"provided to XmlConfigurator");
XPathNavigator xNav = section.CreateNavigator();
if (xNav == null)
throw new ApplicationException(
"Unable to create XPath Navigator");
Type sectionType = Type.GetType((string)
(xNav).Evaluate("string(#configType)"));
XmlSerializer xs = new XmlSerializer(sectionType);
return xs.Deserialize(new XmlNodeReader(section));
}
}
Your config file then has to include a reference to the type that the represents the root element
<ConnectionConfig
configType="MyNamespace.ConnectionConfig, MyNamespace.AssmblyName" >
A sample config file might look like this:
<?xml version="1.0" encoding="utf-8" ?>
<ConnectionConfig
configType="MyNamespace.ConnectionConfig, MyNamespace.AssmblyName" >
<ConnCompanys>
<ConnCompany companyName="CompanyNameHere">
<ConnApps>
<ConnApp applicationName="Athena" vendorName="Oracle" >
<ConnSpecs>
<ConnSpec environments="DEV"
serverName="Athena"
port="1521"
catalog="DatabaseName"
logon="MyUserName"
password="%%552355%8234^kNfllceHGp55X5g==" />
<!-- etc...
And you will need to define the classes that each xml element maps to... using the appropriate XmlSerialization attributes ...
[XmlRoot("ConnectionConfig")]
public class ConnectionConfig
{
private ConnCompanys comps;
[XmlArrayItem(ElementName = "ConnCompany")]
public ConnCompanys ConnCompanys
{
get { return comps; }
set { comps = value; }
}
public ConnApp this[string CompanyName, string AppName]
{ get { return ConnCompanys[CompanyName][AppName]; } }
public ConnSpec this[string CompanyName, string AppName, APPENV env]
{
get
{
return ConnCompanys[CompanyName][AppName, env];
}
}
}
public class ConnCompanys : List<ConnCompany>
{
public ConnCompany this[string companyName]
{
get
{
foreach (ConnCompany comp in this)
if (comp.CompanyName == companyName)
return comp;
return null;
}
}
public bool Contains(string companyName)
{
foreach (ConnCompany comp in this)
if (comp.CompanyName == companyName)
return true;
return false;
}
}
public class ConnCompany
{
#region private state fields
private string compNm;
private ConnApps apps;
#endregion private state fields
#region public properties
[XmlAttribute(DataType = "string", AttributeName = "companyName")]
public string CompanyName
{
get { return compNm; }
set { compNm = value; }
}
[XmlArrayItem(ElementName = "ConnApp")]
public ConnApps ConnApps
{
get { return apps; }
set { apps = value; }
}
#endregion public properties
#region indexers
public ConnApp this[string applicationName]
{ get { return ConnApps[applicationName]; } }
public ConnSpec this[string applicationName, APPENV environment]
{
get
{
foreach (ConnSpec con in this[applicationName].ConnSpecs)
if (con.Environment == environment)
return con;
return null;
}
}
#endregion indexers
}
etc...
My VB isn't up to much sorry but here's how you do it in C#.
C#
public class AppState : IConfigurationSectionHandler
{
static AppState()
{
xmlNode myConfigNode = (XmlNode)ConfigurationManager.GetSection("databases");
}
public object Create(object parent, object context, XmlNode configSection) {
return configSection;
}
}
App.Config
<configuration>
<configSections>
<section name="databases" type="MyAssembly.AppState, MyAssembly" />
</configSections>
<databases>
<database name="DatabaseOne" Value="[value]" />
<database name="DatabaseTwo" Value="[value]" />
</databases>
</configuration>
You might be interested in using a ConfigurationElementCollection where T is the type of the child ConfigurationElements. You can find sample code in C# at http://devpinoy.org/blogs/jakelite/archive/2009/01/10/iconfigurationsectionhandler-is-dead-long-live-iconfigurationsectionhandler.aspx
Cheers!
There's a nice simple way of doing this demonstrated here also:
codeproject.com/KB/XML/xml_config_section.aspx