Friday, December 10, 2010

"Constants" Framework in .Net

Motivation:
  • Constants are spread all over the code, in different files
  • Sometimes they are defined in Constants.cs or AllConstants.cs 
  • Some are defined as constants in the file it is used
  • Some are defined right before being used
  • Sometimes they are not defined at all, just used in place as a number or as a string
  • You have to be familiar with the code in order to tell the value of a particular constant and/or change it
  • Same constants are defined multiple times in different files
  • To make an existing constant being read from a config file you need to write some non trivial code
With the new Framework
  • All constants are defined in a single XML file
  • The framework introduces a very consistent way of declaring and using constants. Strong typing remains ensured. Code duplication is reduced.
  • With the new framework to make a constant editable is as easy as changing the mode from “const” to either mode=“runtime” (always possible to change the value of a “constant” via modifying a configuration XML file and restarting the service) or mode=”runtimeTest” (you can modify the constants at the runtime for testing and debug builds, but you won’t be able to do that in optimized non-test builds).
  • The consumer of a constant does not need to worry about the fact that the value might come from a config file. In other words we get “configurable” constants for free. Some might argue that constants should not be editable, but in my experience this becomes useful for testing/debugging. Playing with timeout/retry values could help expose deadlocks or leaks. A leak that takes 1 day to show up with an interval of 2 minutes could appear after 15 minutes with a 1 second interval.
  • It becomes very easy to get an overview of the constants being used.
How does it work?
All the work is done by the ConstGen.xslt XML conversion: it has been implemented and can be reused by all projects: get it from here.

As the entry argument this XSLT file has an XML project definition file. In difference to the XSLT file above which can be reused for all the projects, each project must define an XML constants definition file. Here is an example:

<?xml version="1.0" encoding="utf-8" ?>
<constants>
  <constant namespace="MyCompany.MyProject" managedName="Constants" access="internal" isStatic="yes">
    <description>All constants for Server.</description>
    <fields>
      <!-- Constants -->
      <field name="VERSION" type="string" value='1.0' mode="runtimeTest" configName="Version" access="internal">
        <description>Current Server version.</description>
      </field>
      <field name="TRANSFER_TIMEOUT" type="int" value="30 * 1000" mode="runtimeTest" configName="Transfer" access="internal">
        <description>Time in millisecods for how long the transfer operation can take.</description>
      </field>
    </fields>
  </constant>

  <constant namespace="MyCompany.MyProject.Common" managedName="Constants" isStatic="yes">
    <description>Common constants for the Call Park Server and Music on Hold functionality.</description>
    <fields>
      <field name="NUMBER_THREADS" type="int" value="Environment.ProcessorCount" mode="runtime" configName="NumberThreads" access="internal">
        <description>Number of running threads in parallel</description>
      </field>
      <field name="RETRY_INTERVAL" type="int" value="3 * 60 * 1000" mode="const" access="internal">
        <description>The retry interval for Enpoint.Establish() in milliseconds.</description>
      </field>
      <field name="RETRY_MAX_ATTEMPTS" type="int" value="10" mode="const" access="private">
        <description>Maximum number of retries to reserve an orbit.</description>
      </field>
    </fields>
  </constant>
</constants>
     
    Next you run XSLT giving as an entry argument the constants definition XML file. As a result a real C# constants file is created. For the XML file above it will look like this.
   
    Now, how do we make this preprocessing step of conversion of an XML file to C# happen? The easiest is to use Visual Studio: it has a built-in XSLT support, so just click on Execute button on opened XSLT file (the one above), it will ask you for an entry XML file, and that's it.
But of course you will want to automate this step. Then, what you need to do is to download MSXSL tool and run it before compiling your project.

If you want to change a value of a constant at runtime, change the corresponding value of the MyApp.exe.config file. Then restart the service. This file should be placed under the same directory where your executable is. Here is an XSLT file that you can use to create the configuration file where you can change the constant values. I.e. "constant" values now will be read from a configuration file. They still will be constants since they will remain same through the execution of the program and you need to restart the program if you change the "constant" value in the configuration file.

The configuration file created by running the XSLT file above and the same XML file will be the following:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <appSettings>

    <add key="Version" value="1.0"/>
    <add key="Transfer" value="30 * 1000"/>
    <add key="NumberThreads" value="Environment.ProcessorCount"/>

  </appSettings>
</configuration>

No comments:

Post a Comment