views:

66

answers:

2

I'm implementing a somewhat complex configuration section for a system monitoring project:

<monitoring>
  <components>
    <component name="Remote Server"
               statusProviderType="ClientEndpoint"
               statusProviderName="endpoint1" />
  </components>
</montioring>

<system.serviceModel>
  <client>
    <endpoint name="endpoint1"/>
    <!-- Config removed for brevity -->
  </client>
</system.serviceModel>

As in the example above, these configuration elements can refer to other configuration elements. In this case, a client endpoint which must implement a pre-determined contract which is part of the monitoring project.

The built-in configuration handling deals with any obvious syntax errors and simple errors where values are outside of a valid range. The problem is where configuration is the source of more complex errors:

  • Referencing an element which does not exist.
  • Referencing a Type which does not meet certain conditions.

Obviously, I wish to pick up on these errors, but where should this validation be done in the application?

I've considered these options so far, but I'm not sure any of them is correct:

  • The configuration element validates itself and throws exceptions when it is read. Keeps everything at a configuration level, but introduces problems when trying to "build" a configuration section to write it to a configuration file.
  • The component which consumes the configuration validates the configuration values when they are passed to it and throws exceptions based on the information received. Allows for more flexibility with configuration elements, but makes it harder to identify where the problem's origin is.
  • The component which consumes the configuration validates the configuration as it is needed by its operation and throws exceptions when configuration is invalid. This nicely separates the behaviour from the configuration, but makes it less obvious when the configuration is the source of the problem.

Additionally, which exceptions are appropriate to throw for the sort of errors I am potentially handling? Bonus points for good reasoning with your answers.

I'm feeling rather clueless with all the options available, but knowing how hard configuration can be to debug with some systems, I really want a sensible solution.

A: 

Use DTD and XML validation tools. Here is the description

Elalfer
Validating the XML is already sufficiently performed by the .NET configuration system. The errors I'm looking to detect are more complex than these.
Programming Hero
A: 

I went away, asked some colleagues, investigated how the .NET classes handle this sort of problem and came to a number of clarifications:

  • Configuration is simply a way to configure object instances, often as simple as specifying default values for new instances. The values available in the configuration file are also typically available to set in code.
  • An improperly configured instance throws InvalidOperationException and deriving classes to indicate an error in the state of the object. It does not indicate where the configuration problem comes from.
  • If the configuration is valid enough to set up an instance from, even if the instance is not able to run correctly, the error is no longer classified as a "configuration file" issue specifically.

Obviously this gives me a number of rules I can stick to, to be happy about my configuration system:

  • If an error can be detected within a value in a configuration file (e.g. a string in an incorrect format, a type which does not implement an interface), the error is a configuration-level error and indicates a problem with the configuration file. The validation should be performed by the configuration section and an exception thrown when the section is read from a configuration file.
  • If the error cannot be detected within a value, it should be possible to initialize an instance from the values without any exceptions being thrown. Avoid throwing exceptions here and consider refactoring classes to move existing exceptions elsewhere. Exceptions at this stage which are not obviously related to configuration are hard to debug as there is often no available state to debug from. If exceptions must be thrown here, they should be wrapped by a configuration-related exception and should cite the element which caused the problem.
  • If any errors occur after configuration has been loaded, the issue is handled by the object instance as an InvalidOperationException or similar problem, as it does not know where the values it works with came from and therefore can only indicate its state is incorrect.

Should anybody else be making complicated configuration, I hope this helps.

Programming Hero