Tuesday, September 22, 2009

System.Configuration & Enum case-insensitivity

Yesterday one of DataObjects.Net 4 customers made a request for the following enhancement: he wrote it would be much more usable if one could write case-insensitive Enum options in DataObjects.Net configuration section. So instead of standard case-sensitive:

<domain upgradeMode="Recreate"/>

he suggested that we should implement support for case-insensitive values also, e.g.:

<domain upgradeMode="recreate"/>

As IMO the suggestion was really usable and I thought it was easy to implement, I decided to make it ASAP. I knew that there are two ways of parsing Enum values: case-sensitive and case-insensitive – both of them are provided by static Enum.Parse member. I thought that we were using case-sensitive one. So I went to Xtensive.Storage.Configuration namespace and found the corresponding code. It was the following:

[ConfigurationProperty(UpgradeModeElementName, IsRequired = false, 
DefaultValue = DomainUpgradeMode.Default)]
public DomainUpgradeMode UpgradeMode
  get { return (DomainUpgradeMode)this[UpgradeModeElementName]; }
  set { this[UpgradeModeElementName] = value; }

As you see, DataObjects.Net 4 doesn’t responsible for Enum value parsing as it expects already parsed Enum value, but not initial string from app.config. But who is responsible for Enum value parsing then? Let’s dig into the System.Configuration assembly.

With .NET Reflector I found that System.Configuration.GenericEnumConverter is the place where string is converted into Enum value. But unfortunately it uses case-sensitive method of parsing strings and there is no way to change this behavior. It is hard-coded by one of microsofties. This means that all developers that use System.Configuration are to write only case-sensitive Enum values in their project configuration files.


The alternative way is to convert all Enum-based properties into string-based ones and parse them manually during ConfigurationElement –> Configuration conversion routine. So we should change the above-mentioned property into the following one:

[ConfigurationProperty(UpgradeModeElementName, IsRequired = false, 
DefaultValue = "Default")]
public string UpgradeMode
  get { return (string)this[UpgradeModeElementName]; }
  set { this[UpgradeModeElementName] = value; }

The second step is to add case-insensitive Enum-parsing logic into DomainConfigurationElement.ToNative() method:

domainConfig.UpgradeMode = (DomainUpgradeMode) Enum.Parse(
  typeof (DomainUpgradeMode), UpgradeMode, true);

That’s it!
Certainly, the same modification is made to all Enum-based configuration properties.

Thanks to Ivan Galkin for the bright idea.


1 comment:

  1. http://stackoverflow.com/questions/8922930/net-custom-configuration-how-to-case-insensitive-parse-an-enum-configurationpro