Global Configuration inProc

In many applications, we try to limit database connections, especially where data rarely change. We can load them once into memory when application starts and refresh only on demand. Such an example can be a table configuration in which we can put all kinds of parameters (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);
    }
}
Sometimes there will be a need to inform other (friendly) modules of the system that configuration changed, for example we need to recalculate or reprocess some data that are dependent (for this purpose 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);
     }
}

In the following example I intentionally omit data access layer with Datacontext, because it does not affect the idea of ​​a solution. 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 we see, 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 *