Global Configuration inProc

In many applications, we are struggling with performance issues. One of the most basic practices is to try to limit database connections, especially where data rarely changes. We can load them once into memory when the application starts and refresh only on demand. We can use table configuration to store the data. We can put all kinds of parameters there (SMTP, servers, ports etc). For the purpose of this article, we define Configuration class with only one simple decimal property holding value involved in some calculations

 
public class Configuration
{
    public decimal GlobalValue { get; set; }
    public override string ToString()
    {
        return string.Format(CultureInfo.InvariantCulture, "GlobalValue = {0}", this.GlobalValue);
    }
}
It’s important to inform other friendly system modules that configuration changed. In this test scenario we need to recalculate some data. For this purpose we can use event based – observer pattern.
We will need also a class (derived from EventArgs) in which we will be able to provide additional information between events
public class ConfigurationChangeEventArgs : EventArgs
{
    public Decimal OldValue { get; private set; }
    public Decimal NewValue { get; private set; }

    public ConfigurationChangeEventArgs(decimal oldValue, decimal newValue)
    {
        this.OldValue = oldValue;
        this.NewValue = newValue;
    }
}

At the beginning, let’s write ConfigurationProvider class which contains Configuration class property and public method LoadConfiguration:

public void LoadConfiguration(Configuration conf)
{
  OnConfigurationChange(this, new ConfigurationChangeEventArgs(Configuration.GlobalValue, conf.GlobalValue));
  Console.WriteLine("ConfigurationProvider is Loading new Configuration " + conf);
  Configuration = conf;
}
When system reloads the configuration ConfigurationChangeEvent is fired:
private void OnConfigurationChange(object sender, ConfigurationChangeEventArgs data)
{
  if (ConfigurationChange != null)
  {
     ConfigurationChange(this, data);
  }
}

Now we create some subscribers:

public class Observer1
{
  public decimal Result { get; set; }

  public void HandleConfigurationChange(object sender, ConfigurationChangeEventArgs data)
  {
     Console.WriteLine("Observer1 - configuration has changed");
     Result = new Random().Next() % 10 * data.NewValue;
     Console.WriteLine("Observer1 - Recalculating Result: " + Result);
  }
}
public class Observer2
{
    public decimal Result { get; set; }

    public void HandleConfigurationChange(object sender, ConfigurationChangeEventArgs data)
    {
       Console.WriteLine("Observer2 - configuration has changed");
       Result = new Random().Next() % 10 * data.NewValue;
       Console.WriteLine("Observer2 - Recalculating Result: " + Result);
     }
}

Putting all together into our scenario we have

internal class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("ENTER NEW VALUE TO RELOAD CONFIGURATION (AND REFRESH SUBSCRIBERS)");

        var conf = new Configuration
        {
            GlobalValue = 100
        };

        var o1 = new Observer1 { Result = 1};
        var o2 = new Observer2 { Result = 1};

        ConfigurationProvider.Instance.LoadConfiguration(conf);

        ConfigurationProvider.Instance.ConfigurationChange += o1.HandleConfigurationChange;
        ConfigurationProvider.Instance.ConfigurationChange += o2.HandleConfigurationChange;

        int val;
        while (int.TryParse(Console.ReadLine(), out val))
        {
            ConfigurationProvider.Instance.LoadConfiguration(new Configuration
            {
                GlobalValue = val
            });
        }
    }
}

global config in proc out
As expected, new value was loaded, all subscribers were notified and made some calculations based on current configuration parameter

Source code is avaliable here

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *