views:

376

answers:

3

I have a console application that is trying to load a CustomConfigurationSection from a web.config file.

The custom configuration section has a custom configuration element that is required. This means that when I load the config section, I expect to see an exception if that config element is not present in the config. The problem is that the .NET framework seems to be completely ignoring the isRequired attribute. So when I load the config section, I just creates an instance of the custom configuration element and sets it on the config section.

My question is, why is this happening? I want the GetSection() method to fire a ConfigurationErrors exception since a required element is missing from the configuration.

Here is how my config section looks.

public class MyConfigSection : ConfigurationSection
{
    [ConfigurationProperty("MyConfigElement", IsRequired = true)]
    public MyConfigElement MyElement
    {
        get { return (MyConfigElement) this["MyConfigElement"]; }
    }
}
public class MyConfigElement : ConfigurationElement
{
    [ConfigurationProperty("MyAttribute", IsRequired = true)]
    public string MyAttribute
    {
        get { return this["MyAttribute"].ToString(); }
    }
}

Here is how I load the config section.

   class Program
    {
        public static Configuration OpenConfigFile(string configPath)
        {
            var configFile = new FileInfo(configPath);
            var vdm = new VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name);
            var wcfm = new WebConfigurationFileMap();
            wcfm.VirtualDirectories.Add("/", vdm);
            return WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
        }

        static void Main(string[] args)
        {
            try{
                string path = @"C:\Users\vrybak\Desktop\Web.config";

                var configManager = OpenConfigFile(path);
                var configSection = configManager.GetSection("MyConfigSection") as MyConfigSection;

                MyConfigElement elem = configSection.MyElement;
            } catch (ConfigurationErrorsException ex){
                Console.WriteLine(ex.ToString());
            }
        }

Here is what my config file looks like.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="MyConfigSection" type="configurationFrameworkTestHarness.MyConfigSection, configurationFrameworkTestHarness" />
  </configSections>

  <MyConfigSection>

  </MyConfigSection>

The wierd part is that if I open the config file and load the section 2 times in a row, I will get the exception that I expect.

var configManager = OpenConfigFile(path);
var configSection = configManager.GetSection("MyConfigSection") as MyConfigSection;
configManager = OpenConfigFile(path);
configSection = configManager.GetSection("MyConfigSection") as MyConfigSection;

If I use the code above, then the exception will fire and tell me that MyConfigElement is required. The question is Why is it not throwing this exception the first time??

A: 

Eric has answered this in the MS Forums

To quote his answer:

The IsRequired member of ConfigurationPropertyAttribute does not work when applied to a child object (deriving from ConfigurationElement)

David Gardiner
I dont think that Eric answered this correctly. You can see my response to him here.http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/710c69e7-0c70-4905-8a5d-448c1e12a2e5?prof=required
Vadim Rybak
It is odd that it worked the second time around. Would be interesting to debug into the .NET framework code to see what is happening under the hood.-dave
David Gardiner
A: 

Did you try assigning it directly to the correct type of variable, i.e. MyConfigSection instead of var? That is the only difference I can see between the two lines of code. (i.e in the second line, var has now taken a specific type).

Jennifer Zouak
Using specific type instead of var doesn't make a difference
Vadim Rybak
+1  A: 

I found that the best workaround for this was to manually iterate through all nested properties that of the ConfigurationElement type and check them myself after getting the section. If an element is required but is not present in the file I just throw a ConfigurationErrorsException.

Here is my code.

private void ProcessMissingElements(ConfigurationElement element)
{
    foreach (PropertyInformation propertyInformation in element.ElementInformation.Properties)
    {
        var complexProperty = propertyInformation.Value as ConfigurationElement;
        if (complexProperty == null) 
            continue;

        if (propertyInformation.IsRequired && !complexProperty.ElementInformation.IsPresent)
            throw new ConfigurationErrorsException("ConfigProperty: [{0}] is required but not present".FormatStr(propertyInformation.Name));
        if (!complexProperty.ElementInformation.IsPresent)
            propertyInformation.Value = null;
        else
            ProcessMissingElements(complexProperty);
    }
}
Vadim Rybak