Cinchoo – Configuration framework – SharedEnvironment, part 1

Shared Environment Configuration

In a situation, where you want to keep and maintain configurations for each  environment (DEV, UAT and PROD etc) separately in a centralized location, attach them to your application and/or switch them at run-time, all these can be done using Cinchoo configuration framework. This is the first of the series of articles about SharedEnvironment in this blog.

Cinchoo framework discover this file (SharedEnvironment.config) in the application base directory if not specified explicitly. It can be overridden by couple of ways

  • appSettings – If you have a file contain shared environment xml in a different location, you can specify them here. Below is the sample
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="AppEnvironment" value="DEV" />
    <add key="SharedEnvironmentConfgiFilePath" value="c:\Temp\NewSharedEnvironments.config"/>
  </appSettings>
</configuration>

  • Run-Time – In cases where SharedEnvironment xml is not in a file or stored in different sources (Database, WebService etc), you can retrieve them and pass it to the framework by subscribing to ChoApplication.GetSharedEnvironmentConfigXml callback. Below is sample

class Program
{
    static void Main(string[] args)
    {
        ChoApplication.GetSharedEnvironmentConfigXml = new Func<string>(() =>
            {
                string xml = null;
                //Go to source and retrieve the xml
                return xml;
            });
    }
}

Your application can be configured to use particular environment by specifying at appSettings as below
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="AppEnvironment" value="DEV" />
    <add key="SharedEnvironmentConfgiFilePath" value="c:\Temp\NewSharedEnvironments.config"/>
  </appSettings>
</configuration>

Now lets walk over the specification of SharedEnvironment.Config file.
<?xml version="1.0"?>
<configuration>
  <sharedEnvironment baseAppSharedConfigDirectory="C:\Config" defaultEnvironment="DEV">
    <environment name="DEV" freeze="true" appFrxFilePath="DEVConfig" >
      <machine>WNYC12D10101</machine>
      <machine>WNYC12D10102</machine>
      <machine>WNYC12D10103</machine>
      <machine>WNYC12D10104</machine>
    </environment>
    <environment name="PROD" appFrxFilePath="C:\Config\PROD\TestApp.config.txt" freeze="true" >
      <machine>SNYC12D10101</machine>
      <machine>100.39.191.175</machine>
    </environment>
    <environment name="UAT" >
      <machine>WNYC1108054621</machine>
      <machine>SNYC*</machine>
    </environment>
  </sharedEnvironment>
</configuration>

  • baseAppSharedConfigDirectory – A configuration directory used by a environment whose appFrxFilePath is not specified or it contains relative file path. In the above samples, environment ‘UAT’ uses this directory to read / store configuration. If not specified, it will be defaulted to application binary base directory.
  • defaultEnvironment – An environment used by any host which is not listed in this xml.
Each environment can be created using ‘environment’ element. In the above sample, we have ‘DEV’, ‘PROD’, and ‘UAT’ environments.
  • name – Name of the environment, mandatory.
  • freeze – true, all the hosts belongs to the environment locked. Can not be overridden by specifying it in appSettings/appEnvironment. false, it can be overridden. Default false. Optional.
  • appFrxFilePath – A file / directory path. Either absolute / relative path. In case of relative path, framework resolves the path in relative to ‘baseAppSharedConfigDirectory’ path. In the sample above, for the ‘DEV’ environment, this path resolved to ‘C:\Config\DEVConfig’. If missing/not specified, the path will be the environment ‘Name’ under ‘baseAppSharedConfigDirectory’. In the sample above, the ‘UAT’ environment will resolve this path to ‘C:\Config\UAT’. It is optional.
Then you can bind hosts to any environment using ‘machine’ element under ‘environment’. Host can be either MachineName or IP Address. Also the those host names can contain wild card characters as well.
Ex: SYNC*, WNYC1002340? etc

Cinchoo – All possible valid INI name values, Part 8

ChoIniDocument

This is the continuation of previous articles about handling INI section. In this section, I’m going to show you all the possible valid INI name values can be given in the INI document

[PRODUCT]
ENVIRONMENT                                                               ;No Value specified
VERSION = 1.002                                                           ;Valid Value specified
ADDRESS = 10 River Road, \
          Orlando, \
          FL 100230.                                                      ;Multi-Line value specified
CONNECTION_STRING1 = "PROVIDER=SQLServer;UserName=xxxx;Password=yyyyy"    ;Value with ';' characters
CONNECTION_STRING2 = "PROVIDER=Oracle;UserName=xxxx;
                      Password=yyyyy"                                     ;Multi-Line Value with ';' characters

 


Cinchoo – INI Parser Settings, Part 7

ChoIniDocument

Reading and writing INI files using Cinchoo framework can be controlled through global INI settings. These settings are available for your to edit at ChoIniSettings.xml file in your application binary folder. It will be created automatically when you run your application, if not exists. Here is the sample INI settings file looks like

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <iniSettings nameValueSeperator="=" commentChars=";#" ignoreValueWhiteSpaces="false" />
</configuration>

Where

  • nameValueSeperator – A character separate the key-value under section. Default value is ‘=’.
  • commentChars – List of INI comment character parser used to identify the comments. Default value is ‘;#’.
  • ignoreValueWhiteSpaces – true, to trim any white-spaces surrounded the value. Otherwise, preserve the white space with the value if any.

Cinchoo – Reading all INI sections, Part 7

ChoIniDocument

This is the continuation of previous articles about handling INI section. In this section, I’ll show you how you can read all the available INI section inside a INI document.. For a sample INI file below

;This is a test INI file.

[PRODUCT]
VERSION=1.002 ;Version Comment
COMPANY=NAG Groups LLC
ADDRESS=10 River Road, \
        Orlando, \
        FL 100230.

[SOFTWARE]
OS1=Windows
ENVIRONMENT=PRODUCTION

Reading all the INI sections can be done as below

    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        foreach (ChoIniSectionNode iniSectionNode in iniDocument.Sections)
        {
            Console.WriteLine(String.Format("Key-Values for {0} Section...", iniSectionNode.Name));
            foreach (KeyValuePair<string, string> keyValue in iniSectionNode.KeyValues)
                    Console.WriteLine("{0} = {1}", keyValue.Key, keyValue.Value);
        }
    }


Cinchoo – Reading all INI section key values, Part 6

ChoIniDocument

This is the continuation of previous articles about handling INI section. In this section, I’ll show you how you can read all the key-values from a INI section. For a sample INI file below

;This is a test INI file.

[PRODUCT]
VERSION=1.002 ;Version Comment
COMPANY=NAG Groups LLC
ADDRESS=10 River Road, \
        Orlando, \
        FL 100230.

Reading all key-values for PRODUCT section can be done as below

    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        ChoIniSectionNode productIniSectionNode;
        if (iniDocument.TryGetSection("PRODUCT", out productIniSectionNode))
        {
            foreach (string key in productIniSectionNode.Keys)
                Console.WriteLine("{0} = {1}", key, productIniSectionNode[key]);
        }
    }

OR

    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        ChoIniSectionNode productIniSectionNode;
        if (iniDocument.TryGetSection("PRODUCT", out productIniSectionNode))
        {
            foreach (KeyValuePair<string, string> keyValue in productIniSectionNode.KeyValues)
                Console.WriteLine("{0} = {1}", keyValue.Key, keyValue.Value);
        }
    }


Cinchoo – Multiline INI values, Part 5

ChoIniDocument

In this section, I’ll show you how you can store and read multiline values from Ini file. According to INI specification, multiline INI values are supported. In the below sample, ADDRESS section value is specified as multiline value. \ char is used to break the line in the value.

;This is a test INI file.

[PRODUCT]
VERSION=1.002 ;Version Comment
COMPANY=NAG Groups LLC
ADDRESS=10 River Road, \
        Orlando, \
        FL 100230.

Try and see the value returned from the below statement…

using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
{
    Console.Writeline(iniDocument["PRODUCT"]["ADDRESS"]);
}


Cinchoo – Application Host, Part 1

ChoApplicationHost

Building single instance application is easy with Cinchoo framework. Create your application and run using ChoApplicationHost as below. Turning your application to Single Instance application is easy through configuration. Here is how you  can do it. Cinchoo framework uses Mutex to perform the singleton application check by default. It can be overridden to perform custom check.

1. Add reference to Cinchoo.Core.dll

2. Add namespace Cinchoo.Core

[RunInstaller(true)] //Optional attribute, to host your application as Windows Service
public class AppHost : ChoApplicationHost
{
    protected override void OnStart(string[] args)
    {
        //TODO: Application Startup code goes here
    }
}

public class Program
{
    static void Main(string[] args)
    {
        ChoApplication.Run(new AppHost(), args);
    }
}

Open the Global Application Settings section in ChoCoreFrx.config file (you can find it in application binary directory), set singleInstanceApp to true.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <globalApplicationSettings singleInstanceApp="true" applicationId="TestApplication" eventLogSourceName="TestApplication" useApplicationDataFolderAsLogFolder="false" appEnvironment="PROD" hostName="WNYC100230012">
    <logFolder>C:\Logs</logFolder>
    <sharedEnvironmentConfigFilePath>c:\Config\sharedEnvConfig.xml</sharedEnvironmentConfigFilePath>
    <appConfigPath>c:\config\TestApplication.xml</appConfigPath>
    <logTimeStampFormat>yyyy-MM-dd hh:mm:ss.fffffff</logTimeStampFormat>
  </globalApplicationSettings>
</configuration>

Override programmatically

Some scenarios you may want to control it programmatically. When it arises, you can do so as below

Method 1:

Subscribe to ApplyFrxParamOverrides eventhandler before ChoApplication.Run() as below.

public class Program
{
    static void Main(string[] args)
    {
        ChoApplication.ApplyFrxParamsOverrides += new EventHandler<ChoFrxParamsEventArgs>(ChoApplication_ApplyFrxParamsOverrides);
        ChoApplication.Run(new AppHost(), args);
    }
    static void ChoApplication_ApplyFrxParamsOverrides(object sender, ChoFrxParamsEventArgs e)
    {
        e.GlobalApplicationSettings.SingleInstanceApp = true;
    }
}

Method 2:

You can override ApplyFrxParamsOverrides method in your AppHost class as below.

[RunInstaller(true)]
public class AppHost : ChoApplicationHost
{
    protected override void OnStart(string[] args)
    {
    }

    protected override void ApplyFrxParamsOverrides(ChoGlobalApplicationSettings globalApplicationSettings, ChoMetaDataFilePathSettings metaDataFilePathSettings)
    {
        globalApplicationSettings.SingleInstanceApp = true;
    }
}
public class Program
{
    static void Main(string[] args)
    {
        ChoApplication.Run(new AppHost(), args);
    }
}

Custom Singleton Instance Check

By default, Cinchoo framework carries out the Singleton instance check using Mutex. In case, if you want to perform your own custom singleton check for your application, it can be done through by hooking your custom routine to ChoApplication type as below

public class Program
{
    static void Main(string[] args)
    {
        ChoApplication.VerifyAnotherInstanceRunning = (() =>
            {
                //TODO: Do your custom singleton instance check here

                return true; //true, already another instance running. Otherwise false.
            });

        ChoApplication.Run<AppHost>(args);
    }
}


Cinchoo – Accessing INI sections, Part 4

ChoIniDocument

In this section, I’ll walk you over accessing different parts of INI document using ChoIniDocument class

Using Indexer

First and easy way, you can use the indexer to access the key-value information if you have key name in hand. This will search for key-value in the nested INI files as well.

For a sample INI files below,

C:\Temp\TestIni1.ini

;This is a test INI file.
;To test its functionality.

[PRODUCT]
VERSION=1.002 ;Version Comment
COMAPNY=NAG Groups LLC ;Company node

[INCLUDE("C:\Temp\TestIncludeIni1.ini")]

C:\Temp\TestIncludeIni1.ini

[SOFTWARE]
OS1=MAC
OS2=Windows7

Code below shows how to access name-values using indexer

private static void LookupNameValues()
{
    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        //Lookup PRODUCT/VERSION
        Console.Writeline(iniDocument["PRODUCT"]["VERSION"]);

        //Lookup SOFTWARE/OS1 in nested INI file
        Console.Writeline(iniDocument["SOFTWARE"]["OS1"]);
    }
}

Using Section Access Methods

You can access INI sections using one of the below overload methods

public ChoIniSectionNode GetSection(string sectionName);
public bool TryGetSection(string sectionName, out ChoIniSectionNode section);


Cinchoo – Saving INI file, Part 3

ChoIniDocument

In this section, I’ll talk about on how to create INI document programmatically and save them. ChoIniDocument class provides abundant set of members helps you to create and add different types of   INI elements to the document.  Below are the different sections of INI document

  • ChoIniDocument – An INI document, contains heading ChoIniCommentNodes followed by series ChoIniSectionNodes, ChoIncludeIniSectionNodes, ChoIniCommentNodes or ChoIniNewLineNodes
  • ChoIniCommentNode – An INI comment node
  • ChoIniNewLineNode – An INI new line node
  • ChoIniSectionNode – An INI section node, may contain a Inline ChoIniCommentNode followed by series of ChoIniNewLineNodes, ChoIniCommentNodes, ChoIniNameValueNodes
  • ChoIniNameValueNode – An INI name value node
  • ChoIniIncludeFileNode – INI Include file node, it contains the same set of elements as ChoIniDocument contains.

Here I’ll show you on how to create a sample INI file programmatically

private static void CreateINIFile()
{
    ChoIniDocument.Clear(@"C:\Temp\TestIni1.ini");
    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        //Create INI document level comments
        iniDocument.AppendHeadingComment("This is a test INI file.");
        iniDocument.AppendHeadingComment("To test its functionality.");
        iniDocument.AppendHeadingNewLine();

        //Create and add PRODUCT section
        ChoIniSectionNode section = iniDocument.CreateSection("PRODUCT");
        iniDocument.AddSection(section);

        //Create and add VERSION name value to PRODUCT section
        ChoIniNameValueNode versionNode = section.AddNameValueNode("VERSION", "1.002");

        //Create and add COMPANY name value node to PRODUCT section
        ChoIniNameValueNode companyNode = section.AddNameValueNode("COMPANY", "NAG Groups LLC");

        //Add a newline node
        section.AddNewLineNode();

        //Create and add INI include node
        ChoIniIncludeFileNode iniIncludeFileNode = iniDocument.CreateIniIncludeFileNode(@"C:\Temp\TestIncludeIni1.ini");
        iniDocument.AddIniIncludeFileNode(iniIncludeFileNode);

        //Create and add SOFTWARE section to included node
        ChoIniSectionNode softwareSection = iniIncludeFileNode.CreateSection("SOFTWARE");
        iniIncludeFileNode.AddSection(softwareSection);

        //Create and add OS1 name value node to SOFTWARE section
        softwareSection.AddNameValueNode("OS1", "MAC");

        //Create and add OS2 name value node to SOFTWARE section
        softwareSection.AddNameValueNode("OS2", "Windows7");

        Console.WriteLine(iniDocument.ToString());

        iniDocument.Save();
    }
}

It creates the below two INI files as below

C:\Temp\TestIni1.ini

;This is a test INI file.
;To test its functionality.

[PRODUCT]
VERSION=1.002 ;Version Comment
COMAPNY=NAG Groups LLC ;Company node

[INCLUDE("C:\Temp\TestIncludeIni1.ini")]

C:\Temp\TestIncludeIni1.ini

[SOFTWARE]
OS1=MAC
OS2=Windows7


Cinchoo – Reading Nested INI files, Part 2

ChoIniDocument

In this section, I’ll talk about one of the most important feature Cinchoo framework provides in reading INI file is the Nested INI file support. You can break down large INI file and manage them easily. ChoIniDocument able to read the nested ini files and gives you object structure in memory.

Nested INI files can be setup as below

Main.ini file

;This is a test INI file.

[PRODUCT]
VERSION=1.002
COMAPNY=NAG Groups LLC

[INCLUDE("C:\Temp\TestInclude.ini")]

[ENVIRONMENT]
VERSION=1.0.0.1
PATH=C:\WINDOWS

In main.ini file, we included TestInclude.ini file using [INCLUDE] tag. Tag is case-sensitive. Also the path can specified as absolute/relative path.

TestInclude.ini file

[SOFTWARE]
OS1=MAC
OS2=Windows7

Loading Main.ini file using ChoIniDocument.Load() will load all the included INI files and build the tree in memory seamlessly.

static void Main(string[] args)
{
    using (ChoIniDocument iniDocument = ChoIniDocument.Load(@"C:\Temp\TestIni1.ini"))
    {
        Console.WriteLine(iniDocument.ToString());
    }
}

PS: Make sure all the main as well as included INI files contains distinct INI sections (no duplicate section allowed). Otherwise load will fails with exception.


Follow

Get every new post delivered to your Inbox.