Reputation: 7356
I am trying to create a custom section group in my web.config. It is mostly working, but is failing out with the following error:
Unrecognized element 'add'. (web.config line 736) at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)....
There may be other errors in the code, but this is the part I cannot get passed.
Here is my web.config XML:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="systemEmailsGroup">
<section name="systemEmails" type="SystemEmailsConfiguration" />
</sectionGroup>
</configSections>
<!-- lots of other stuff -->
<systemEmailsGroup>
<systemEmails>
<emails>
<email name="SystemEmail01" defaultAddress="[email protected]" defaultName="John Doe 01" />
<email name="SystemEmail02" source="UserName" username="Username02" defaultAddress="[email protected]" defaultName="Jane Doe 02" />
<email name="SystemEmail03" defaultAddress="[email protected]" defaultName="John Doe 03" />
<email name="SystemEmail04" source="UserName" username="Username04" />
<email name="SystemEmail05" source="RoleName" rolename="administrators" defaultEmailName="SystemEmail02" />
<email name="SystemEmailGroup01" source="Group">
<add name="SystemEmail06" defaultAddress="[email protected]" defaultName="Jane Doe 06" />
<!-- ^^^ LINE 736 ^^^ -->
<add name="SystemEmail07" defaultAddress="[email protected]" defaultName="John Doe 07" />
<add name="SystemEmail08" defaultAddress="[email protected]" defaultName="Jane Doe 08" />
</email>
</emails>
</systemEmails>
</systemEmailsGroup>
</configuration>
Note that I marked the line 736 mentioned in the error.
My class structure is below. The first inherits ConfigurationSection
, the second inherits ConfigurationElementCollection
, and the last inherits ConfigurationElement
. After that is an extension class for the SystemEmailsElement
type. It's probably not relevant to the error, but I will include it just for completion sake.
public class SystemEmailsConfiguration : ConfigurationSection
{
public static SystemEmailsConfiguration GetConfig()
{
return ConfigurationManager.GetSection("systemEmailsGroup/systemEmails") as SystemEmailsConfiguration;
}
[ConfigurationProperty("emails", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(SystemEmailsElementCollection),
AddItemName = "email", ClearItemsName = "clear", RemoveItemName = "remove")]
public SystemEmailsElementCollection Emails
{
get
{
return base["emails"] as SystemEmailsElementCollection;
}
}
}
public enum SystemEmailsSource
{
None = 0,
UserName = 1,
RoleName = 2,
Group = 3
}
public class SystemEmailsElementCollection : ConfigurationElementCollection, IEnumerable<SystemEmailsElement>
{
List<SystemEmailsElement> _elements = new List<SystemEmailsElement>();
public SystemEmailsElement this[int index]
{
get
{
return _elements[index];
}
set
{
if (index >= 0 && index < _elements.Count)
{
_elements.RemoveAt(index);
}
_elements.Insert(index, value);
}
}
public SystemEmailsElement this[string key]
{
get
{
return _elements.Where(e => e.Name == key).FirstOrDefault();
}
set
{
var el = _elements.Where(e => e.Name == key).FirstOrDefault();
if (el != null)
{
int index = _elements.IndexOf(el);
_elements.RemoveAt(index);
_elements.Insert(index, value);
}
else
_elements.Add(value);
}
}
protected override ConfigurationElement CreateNewElement()
{
var el = new SystemEmailsElement();
_elements.Add(el);
return el;
}
protected override object GetElementKey(ConfigurationElement element)
{
return _elements.Find(e => e.Equals(element)).Name;
}
public new IEnumerator<SystemEmailsElement> GetEnumerator()
{
return _elements.GetEnumerator();
}
}
public class SystemEmailsElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name
{
get
{
return this["name"] as string;
}
}
[ConfigurationProperty("source", DefaultValue = SystemEmailsSource.None)]
public SystemEmailsSource Source
{
get
{
return (this["source"] != null) ? (SystemEmailsSource)this["source"] : SystemEmailsSource.None;
}
}
[ConfigurationProperty("defaultAddress")]
public string DefaultAddress
{
get
{
return this["defaultAddress"] as string;
}
}
[ConfigurationProperty("defaultName")]
public string DefaultName
{
get
{
return this["defaultName"] as string;
}
}
[ConfigurationProperty("defaultEmailName")]
public string DefaultEmailName
{
get
{
return this["defaultEmailName"] as string;
}
}
[ConfigurationProperty("username")]
public string UserName
{
get
{
return this["username"] as string;
}
}
[ConfigurationProperty("rolename")]
public string RoleName
{
get
{
return this["rolename"] as string;
}
}
[ConfigurationProperty("email")]
[ConfigurationCollection(typeof(SystemEmailsElementCollection),
AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
public SystemEmailsElementCollection Emails
{
get
{
return base["email"] as SystemEmailsElementCollection;
}
}
}
public static class SystemEmailsElementExtenstions
{
/// <summary>
/// Returns true if the SystemEmailsElement may contain a group of email addresses.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool IsGroup(this SystemEmailsElement value)
{
return (value.Source == SystemEmailsSource.Group || value.Source == SystemEmailsSource.RoleName);
}
/// <summary>
/// Gets the email or emails result of this section as a MailAddressCollection.
/// Returns an empty MailAddressCollection if not able to create any MailAddress objects.
/// </summary>
/// <returns></returns>
public static MailAddressCollection GetEmails(this SystemEmailsElement value)
{
var emails = new MailAddressCollection();
MailAddress eml = null;
if (value.IsGroup())
{
switch (value.Source)
{
case SystemEmailsSource.RoleName:
if (value.RoleName != null)
{
foreach (UsersNames user in AppPublic.GetUsersByRole(value.RoleName))
{
eml = AppPublic.GetEmailByUserID(user.UserId);
if (eml != null)
emails.Add(eml);
}
}
break;
default: //Group
foreach (var el in value.Emails)
{
foreach (MailAddress e in el.GetEmails())
emails.Add(e);
}
break;
}
}
else
{
emails.Add(value.GetEmail());
}
if (emails.Count == 0)
{
eml = value.CreateEmailFromDefaults();
if (eml != null)
emails.Add(eml);
}
return emails;
}
/// <summary>
/// Gets the email result of this section or the first item in a group as a MailAddress object.
/// Returns null if not able to create the MailAddress.
/// </summary>
/// <returns></returns>
public static MailAddress GetEmail(this SystemEmailsElement value)
{
if (value.IsGroup())
{
return value.GetEmails().FirstOrDefault();
}
else
{
MailAddress eml = null;
if (value.Source == SystemEmailsSource.UserName)
{
if (value.UserName != null)
eml = AppPublic.GetEmailByUserName(value.UserName);
}
if (eml == null)
eml = CreateEmailFromDefaults(value);
return eml;
}
}
/// <summary>
/// Creates a mail address object using the default attribute values from the SystemEmailElement.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static MailAddress CreateEmailFromDefaults(this SystemEmailsElement value)
{
MailAddress eml = null;
//DefaultEmailName takes precedence.
if (value.DefaultEmailName != null)
{
var el = SystemEmailsConfiguration.GetConfig().Emails[value.DefaultEmailName];
if (el != null)
eml = el.GetEmail();
}
//Fall back to DefaultAddress.
if (eml == null && value.DefaultAddress != null)
{
if (value.DefaultName == null)
eml = new MailAddress(value.DefaultAddress);
else
eml = new MailAddress(value.DefaultAddress, value.DefaultName);
}
return eml;
}
}
In an ideal world, the <add>
nodes would be renamed to <email>
nodes, and this code would be recursive and allow any (theoretical) number of node depths.
But if I could just get the first <add>
level working that would great. I've been spinning my wheels on this for hours trying to find the right combination of attributes, signatures, XML, etc.
Thanks!!
Upvotes: 1
Views: 770
Reputation: 101493
To fix your immediate error, you just need to add wrapping <email>
tag to your <add/>
elements. That is because your SystemEmailsElement
contains Emails
property which is collection with root tag defined as "email" (via [ConfigurationProperty("email")]
). Like this:
<systemEmails>
<emails>
<email name="SystemEmail01" defaultAddress="[email protected]" defaultName="John Doe 01" />
<email name="SystemEmail02" source="UserName" username="Username02" defaultAddress="[email protected]" defaultName="Jane Doe 02" />
<email name="SystemEmail03" defaultAddress="[email protected]" defaultName="John Doe 03" />
<email name="SystemEmail04" source="UserName" username="Username04" />
<email name="SystemEmail05" source="RoleName" rolename="administrators" defaultEmailName="SystemEmail02" />
<email name="SystemEmailGroup01" source="Group">
<email>
<add name="SystemEmail06" defaultAddress="[email protected]" defaultName="Jane Doe 06" />
<!-- ^^^ LINE 736 ^^^ -->
<add name="SystemEmail07" defaultAddress="[email protected]" defaultName="John Doe 07" />
<add name="SystemEmail08" defaultAddress="[email protected]" defaultName="Jane Doe 08" />
</email>
</email>
</emails>
</systemEmails>
Now, to make it work like in ideal world, you can utilize IsDefaultCollection
property of ConfigurationProperty
attribute like this:
[ConfigurationProperty("", IsDefaultCollection = true)]
[ConfigurationCollection(typeof (SystemEmailsElementCollection),
AddItemName = "email")]
public SystemEmailsElementCollection Emails
{
get { return base[""] as SystemEmailsElementCollection; }
}
This will allow you to create recursive email nodes the way you would expect to:
<emails>
<email name="SystemEmail01" defaultAddress="[email protected]" defaultName="John Doe 01" />
<email name="SystemEmail02" source="UserName" username="Username02" defaultAddress="[email protected]" defaultName="Jane Doe 02" />
<email name="SystemEmail03" defaultAddress="[email protected]" defaultName="John Doe 03" />
<email name="SystemEmail04" source="UserName" username="Username04" />
<email name="SystemEmail05" source="RoleName" rolename="administrators" defaultEmailName="SystemEmail02" />
<email name="SystemEmailGroup01" source="Group">
<email name="SystemEmail06" defaultAddress="[email protected]" defaultName="Jane Doe 06">
<email name="SystemEmail04" source="UserName" username="Username04" />
<email name="SystemEmail05" source="RoleName" rolename="administrators" defaultEmailName="SystemEmail02" />
</email>
<!-- ^^^ LINE 736 ^^^ -->
<email name="SystemEmail07" defaultAddress="[email protected]" defaultName="John Doe 07" />
<email name="SystemEmail08" defaultAddress="[email protected]" defaultName="Jane Doe 08" />
</email>
</emails>
Upvotes: 2