Category Archives: Shell

Cinchoo – Simplified File Type Associations Development

Download sample – 80.7 KB

1. Introduction

Cinchoo is the application framework for .NET. One of the main functionality it provides to the users is application configuration management. It offers rich base framework classes to build .NET applications targeted on Windows platform.

In this article, I’m going to illustrate how to extend your application to register itself to associate to a file type and how the application can receive the file information when double-clicked on a file from Windows Explorer, etc. It is a simpler, fluent model for developing shell extension context menus rapidly. Making it as library letting you to concentrate yourself on the core development tasks.

2. Requirement

This functionality is written in C# for the .NET 4.0 Framework. It is part of Cinchoo framework, which is a great library with lot of features like Configuration Management, common ApplicationHost, Shell features, etc.

3. How It Works

File associations control the following functionality:

  • Which application launches when a user double-clicks a file
  • Which icon appears for a file by default
  • How the file type appears when viewed in Windows Explorer

Application developers can use file associations to control how the Shell treats custom file types, or to associate an application with existing file types. For example, when an application is installed, the application can check for the presence of existing file associations, and either create or override those file associations.

4. When You Should Implement File Associations

Applications can use files for various purposes: some files are used exclusively by the application, and are not typically accessed by users, while other files are created by the user and are often opened, searched for, and viewed from the Shell.

Unless your custom file type is used exclusively by the application, you should implement file associations for it. As a general rule, implement file associations for your custom file type if you expect the user to interact directly with these files in any way. That includes using the Shell to browse and open the files, searching the content or properties of the files, and previewing the files.

5. “Hello World” Sample

Let’s begin by looking into a simple example of an creating an application registering and opening the ‘.hlw’ files. The screenshot shows how our sample application registers itself to ‘.hlw‘ file types.

Figure 5.1 Screenshot of ‘.hlw’ file type association

When a user double clicks this file, our sample application will be launched and displays the window with the referenced file information.

Figure 5.2 Screenshot of sample application Main Window

  • Download the latest Cinchoo binary here. (Nuget Command: Install-Package Cinchoo)
  • Open VS.NET 2010 or higher
  • Create a sample VS.NET (.NET Framework 4) WinForm/Console Application project
  • Add reference to Cinchoo.Core.dll
  • Use the Cinchoo.Core.Shell namespace

Listing 5.1 Defining File Associations

[assembly: ChoShellFileAssociation(".hlw", Description = "Hello World! Document")]

The above code illustrates how to specify file associations in the sample application using ChoShellFileAssociationAttribute assembly level attribute. It can be defined either in AssemblyInfo.cs file or any class definition file. In this example, it is defined to use ‘.hlk’ file types with optional ‘Hello World! Document’ description.

If you want to leverage the Cinchoo framework registration process, you must define and use ChoApplicationHost derived class as shown below.

Listing 5.2 Application host object

[ChoApplicationHost]
public class AppHost : ChoApplicationHost
{
    public override object MainWindowObject
    {
        get
        {
            return new MainForm();
        }
    }
}

The purpose of this class is to enable your application self-installable file type association program.

Finally, let’s write the main entry code as below.

Listing 5.3 Main Method

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

That’s all. Your application is now ready to be register-able as application to open ‘.hlw’ files.

The sample runs below shows how to register/unregister the sample application to file types

Listing 5.4 FileTypeAssociationExample.exe with /#SE:Register

>FileTypeAssociationExample.exe /#SE:Register

The above command line argument lets you register your application to the shell.

Listing 5.5 FileTypeAssociationExample.exe with /#SE:Unregister

>FileTypeAssociationExample.exe /#SE:Unregister

To unregister the application, pass /#SE:Unregister command line argument to the application.

6. ChoShellFileAssociationAttribute

This attribute is applied at the assembly level to the application to specify what file types are to be associated. You can have multiple definitions of this attribute in an application to register to multiple file types.

6.1 Extension

Specify file type, such as *.txt files, file classes such as ‘text files’, folders, drives, etc. to which the application will be registered to. Possible values can be ‘.hlw’ or ‘hlw’.

6.2 ProgID

The name uniquely identifies the file type. By default, ‘{Ext}File’ will be used as ProgID. If your application name isn’t short, specify abbreviation of it as ProgID. The proper format of a ProgID key name is [Vendor or Application].[Component].[Version], separated by periods and with no spaces, as in Word.Document.6.

6.3 Description

Short description of the file type. By default, ‘{Ext} Document’ will be used as description.

6.4 DefaultIcon

Path to the icon file to set as default icon that you want to display for file types associated with this ProgID. By default, your application icon will be set as default icon.

6.5 DefaultIconIndex

If your application executable contains multiple icons, you can use one of them as default icon to the file type associated by specifying the icon index. There is no straight approach to add multiple icons to .NET application. But the below article explains the steps to add some:

6.6 AdditionalCommandLineArgs

Specify any additional command line arguments required when the associated application launched. It is optional.

6.7 DefaultArgSwitch

Optional command line argument switch you want to specify to the default context file argument.

7. Registration Steps

7.1 Self-Installable

If your application builds using Cinchoo framework application host, your application is self-installable. Make sure to run the application in Administrator (elevated) privilege mode in order to register it successfully.

First, define an application host object as below.

Listing 7.1.1 Application host object

[ChoApplicationHost]
public class AppHost : ChoApplicationHost
{
}

The purpose of this class is to enable your application as self-installable program. Then write the main entry code as below to complete the application as self-installable program.

Listing 7.1.2 Main Method

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

7.2 Custom Installation

In some cases, you may want to control and customize the registration process. This section will talk about the commands available to accomplish the installation of file type associations.

Cinchoo exposes methods via ChoShellFileAssociation class to discover, register and unregister file associations.

7.2.1 Register

This method is used to discover all the file type association definitions available in your application and register them with the shell.

7.2.2 Unregister

This method is used to unregister all the registered file type associations.

Advertisements

Cinchoo – Simplified Shell Context Menu Extensions development

Download Samples.zip – 14.5 KB

1. Introduction

Cinchoo is the application framework for .NET. One of the main functionality it provides to the users is application configuration management. It offers rich base framework classes to build .NET applications targeted on Windows platform.

In this article, I’m going to illustrate how to extend the Windows shell via context menu using Cinchoo library. These context menus must be for a specific file type, such as *.pdf files, drives, folders and more. This provides a way to customize Windows shell functionality through Windows Explorer. It is a simpler, fluent model for developing shell extension context menus rapidly. Making it as library letting you to concentrate yourself on the core development tasks.

2. Requirement

This functionality is written in C# for the .NET 4.0 Framework. It is part of Cinchoo framework, which is a great library with lot of features like Configuration Management, common ApplicationHost, Shell features etc.

3. “Hello World!” Sample

Lets begin by looking into a simple example of an creating shell extension application with ‘Hello World’ context menu attached to any file (*) type.

Figure 3.1 Screenshot of ‘Hello World’ shell context menu

ShellEx1

  • Download the latest Cinchoo binary here. (Nuget Command: Install-Package Cinchoo)
  • Open VS.NET 2010 or higher
  • Create a sample VS.NET (.NET Framework 4) WinForm/Console Application project
  • Add reference to Cinchoo.Core.dll
  • Use the Cinchoo.Core.Shell namespace
  • Copy and paste the below Shell Extension object

Listing 3.1 Defining Shell Extension Object

[ChoShellExtension]
public class HelloWorldShellExt
{
    [ChoShellExtensionContextMenu("*")]
    public static void HelloWorld(string[] args)
    {
        MessageBox.Show(args[0]);
    }
}

The code above illustrates about defining shell extension object. First thing define a shell extension class (ex. HelloWorldShellExt) and it must be decorated with ChoShellExtensionAttribute to complete the definition. Define a context menu method (ex. HelloWorld) decorated with ChoShellExtensionContextMenuAttribute. In this sample, this method is defined to be called for any file type (*). When a user right click on a file in the Windows Explorer and clicked the ‘Hello World’ context menu, this method will be called with the referenced filepath.

Next define a application host object as below,

Listing 3.2 Application host object

[ChoApplicationHost]
public class AppHost : ChoApplicationHost
{
}

The purpose of this class is to enable your application self-installable shell extension program. The above code illustrates about defining one.

Finally, lets write the main entry code as below

Listing 3.3 Main Method

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

Thats all, your application is now ready to be installable as shell extension and called by Shell when context menu is clicked.

Listing 3.4 HelloWorld.exe with /#SE:Register

>HelloWorld.exe /#SE:Register

The above command line argument lets you register your application to the shell.

Listing 3.5 HelloWorld.exe with /#SE:Unregister

>HelloWorld.exe /#SE:Unregister

To unregister the application, pass /#SE:Unregister command line argument to the application.

4. Defining Shell Extension Object

4.1 Attributes

4.1.1 ChoShellExtension

This attribute is applied to the class containing shell extension context menu methods. This class will be discovered by Cinchoo framework during installation, invocation of shell extension methods.

4.1.2 ChoShellExtensionContextMenu

This attribute can be applied to the methods of the shell extension class to designate them as shell extension methods. This attribute designate the methods to receive the command when the user clicks on the context menu from Windows explorer. You can define multiple shell extension handler methods using this attribute for any file types.

4.1.2.1 FileType

Specify file type, such as *.txt files, file classes such as ‘text files’, folders, drives etc. to which the context menu handlers will be registered to.

4.1.2.2 MenuText

Specifies the context menu text. It is optional. If not specified, method name will be used as context menu text.

4.1.2.3 Icon

Specifies the context menu icon. It is optional. If not specified, application icon will be used.

4.1.2.4 IconIndex

If your application executable contains multiple icons, you can use one of them for context menu by specifing the icon index. There is no straight approach to add multiple icons to .NET application. But the below article explains the steps to add some

http://einaregilsson.com/add-multiple-icons-to-a-dotnet-application/

4.1.2.5 ShellKeyName

Specify the registry key name. It is optional. If not specified, method name will be used as shell key name.

4.1.2.6  AdditionalCommandLineArgs

Specify any additional context information required to process the request. It is optional. Framework automatically remembers and pass these information to the handler.

5. Installing Shell Extension Object

5.1 Self-Installable

If your application build using Cinchoo framework application host, your application is self-installable. Make sure to run the application in Administrator privilege mode in order to register it successfully.

First define a application host object as below

Listing 5.1 Application host object

[ChoApplicationHost]
public class AppHost : ChoApplicationHost
{
}

The purpose of this class is to enable your application as self-installable shell extension program. Then write the main entry code as below to complete the application as self-installable program.

Listing 5.2 Main Method

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

5.2 Custom Installation

Some cases you may want to control and customize the installation of Shell Extension objects. This section will talk about the commands available to accomplish the installation of shell extension objects.

Cinchoo exposes methods via ChoShellExtension class to discover, register and unregister shell extension objects.

5.2.1 Register

This method used to discover all the shell extension objects available in your application and register them with the shell.

5.2.2 Unregister

This method used to unregister all the registered shell extension handlers.

Cinchoo – Simplified Command Line Argument Parser

Download Samples.zip

Contents

1. Introduction

Cinchoo is the application framework for .NET. One of the main functionalities it provides to the users is application configuration management. Application configuration is the information that application reads and/or writes at run-time from the source.

Most programs accept command line arguments in some forms. It is repetitive and boring task to be programmed to parse and consume the command line arguments. Making it as library letting you to concentrate yourself on the core development tasks. There are many parsers available to use and does the job for you. Cinchoo is one among them, but very easy to use in your project. Try and feel for yourself.

Cinchoo provides a clean and easy API to consume command line arguments. It allows you

  1. To display usage text
  2. Way to report syntex errors
  3. Type-safe object management
  4. Support of value converters
  5. Support of custom validations
  6. Read commandline parameters from file etc. 

2. Requirement

This command line library is written in C# for the .NET 4.0 Framework. It is part of Cinchoo framework, which is a great library with lot of features like Configuration Management, common ApplicationHost, Shell features etc.

3. “Hello World!” Sample

Lets begin by looking into a simple example of an application accepting two command line arguments name (-name) and message (-msg). name is required argument and msg is optional argument with default value “Good Morning”. If msg is not passed, it will take the default value.

  • Download the latest Cinchoo binary here. (Nuget Command: Install-Package Cinchoo)
  • Open VS.NET 2010 or higher
  • Create a sample VS.NET (.NET Framework 4) Console Application project
  • Add reference to Cinchoo.Core.dll
  • Use the Cinchoo.Core.Shell namespace
  • Copy and paste the below command line object

Listing 3.1 Defining Command Line Object

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoCommandLineArg("name", IsRequired = true, Description = "Name of the person.")]
    public string Name
    {
        get;
        set;
    }
    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
    public string Message
    {
        get;
        set;
    }

    public override string ToString()
    {
        return "{0}! {1}.".FormatString(Message, Name);
    }
}

The code above illustrates about defining command line argument object. First thing define a command line argument (ex. HelloWorldCmdLineParams) class from ChoCommandLineArgObject, it indicates that this object is a command line argument object. And it must be decorated with ChoCommandLineArgObjectAttribute to complete the definition. In this example, we specify the name of application and copyright message. These values are used by parser to display the formatted message on the console window. If these options are not specified, AssemblyTitle and AssemblyCopyright of the entry assembly will be defaulted to these members respectively.

Define command line argument members name and msg either as public fields or properies with get and set in it. Decorate them with ChoCommandLineArg attribute to indicate that they are command line arguments. In this sample, name property is given name as command line switch with IsRequired as true. It means that this argument must be passed with value as command line argument to this executable when it runs. Description is specified to give short help text to this option. Message property is given msg switch name with DefaultValue. It is an optional command line argument, if not passed with value, it will be defaulted to “Good Morning” text.

It is very simple and clear way of specifying command line options using attributes.

Listing 3.2 Main Method

class Program
{
    static void Main(string[] args)
    {
        HelloWorldCmdLineParams cmdLineParams = new HelloWorldCmdLineParams();
        Console.WriteLine(cmdLineParams.ToString());
    }
}

We start by creating new instance of HelloWorldCmdLineParams object, That all. All the heavy lifting of parsing and loading command line arguments to the object done by the parser under the hood. If you run the executable with name argument value as Raj, it will display “Good Morning! Raj.”

Listed below are test runs of the programs with different set of arguments and its output.

Listing 3.3 Test1.exe with no arguments

>Test1.exe
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Missing arg value for 'name' required command line switch.

Test1.exe [/msg:<string>] /name:<string>

        /msg    Greeting message.
        /name   Name of the person.

Listing 3.4 Test1.exe with /?

>Test1.exe /?
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Test1.exe [/msg:<string>] /name:<string>

        /msg    Greeting message.
        /name   Name of the person.

Listing 3.5 Test1.exe with -name argument

>Test1.exe /name:Raj
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Good Morning! Raj.

Listing 3.6 Test1.exe with quoted argument

>Test1.exe /name:"Raj Nagalingam"
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Good Morning! Raj Nagalingam.

Listing 3.7 Test1.exe with -name and -msg arguments

>Test1.exe /name:"Raj Nagalingam" /msg:"Hello world"
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Hello world! Raj Nagalingam.

Listing 3.8 Test1.exe with error conditions

>Test1.exe /name:" " /msg:"Hello world"
Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

Missing arg value for 'name' required command line switch.

ConsoleApplication2.exe [/msg:<string>] /name:<string>

        /msg    Greeting message.
        /name   Name of the person.

So far we have seen some of the samples of using Command line arguments in the executable. Try with some other combinations by yourself to test it out.

4. Types of Command Line arguments

There are two types of command line arguments available to choose from

  1. Positional Command Line Arguments
  2. Switch Named Command Line Arguments

4.1 Positional Command Line Argument

It is an argument defined to accept value from command line arguments from a specified position. Position starts with value 1. A command line object member decorated with ChoPositionalCommandLineArgAttribute will be called positional argument.

Listing 4.1 Command Line Argument Object with Positional Arguments

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "Pos1")]
    public string PosArg1;

    [ChoPositionalCommandLineArg(2, "Pos2")]
    public string PosArg2;

    [ChoCommandLineArg("name1", Aliases="n1, m", IsRequired = true, Description = "Name of the person.")]
    public string Name;

    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
    public string Message
    {
        get;
        set;
    }
}

In the sample above illustrates that PosArg1 and PosArg2 are positional command line arguments. The parser looks at the passed command line arguments, load them with appropriate positional values to them.

Listing 4.2 Test1.exe with positional arguments

>Test1.exe CPos1 /name:"Raj" /msg:"Hello world" CPos2

Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

-- ConsoleApplication2.HelloWorldCmdLineParams State --
        Message: Hello world
        PosArg1: CPos1
        PosArg2: CPos2
        Name: Raj

After executing the program with the above command line argument, the above object members PosArg1 and PosArg2 will be loaded with APos1 and APos2 values. Please note, the positional argument values are mixed up with Switch Named command line arguments. When it comes to parse and load the positional arguments, parser identifies position arguments in the order from left to right starting with position 1 and loads them.

4.2 Switch Named Command Line Argument

It is an argument defined to accept value from command line arguments for a specified command line switch. A command line object member decorated with ChoCommandLineArgAttribute will be called switch named command line argument.

Listing 4.3 Command Line Argument Object with Switch Named Arguments

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "Pos1")]
    public string PosArg1;

    [ChoPositionalCommandLineArg(2, "Pos2")]
    public string PosArg2;

    [ChoCommandLineArg("name", Aliases="n, m", IsRequired = true, Description = "Name of the person.")]
    public string Name;

    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
    public string Message
    {
        get;
        set;
    }
}

In the sample above illustrates that Name and Message are switch named command line arguments. The parser looks at the passed command line arguments for the switches ‘name’ and ‘msg’, load those arguments with the matching switch to the corresponding members in the command line object.

Listing 4.4 Test1.exe with positional arguments

>Test1.exe CPos1 /name:"Raj" /msg:"Hello world" CPos2

Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

-- ConsoleApplication2.HelloWorldCmdLineParams State --
        Message: Hello world
        PosArg1: CPos1
        PosArg2: CPos2
        Name: Raj

After executing the program with the above command line argument, the above object members Name and Message will be loaded with ‘Raj’ and ‘Hello World’ values.

5. Defining Command Line Argument Object

5.1 Attributes

5.1.1 ChoCommandLineArgObjectAttribute

This attribute is applied to the class which will recieve and loaded with command line arguments, ie. the class defining all the command line arguments available to the program. This object will reveive the values specified in the command line arguments to the executable.

  • ApplicationName – Optional. Application name. If not specified, it will be defaulted to AssemblyTitle. If AssemblyTitle is empty, it will defaulted to entry assembly Executable Name.
  • Copyright – Optional. Copyright information. If not specified, it will be defaulted to entry AssemblyCopyright.
  • Description – Optional. Description information. If not specified, it will be defaulted to entry AssemblyDescription.
  • Version – Optional. Version information. If not specified, it will be defaulted to entry AssemblyVersion.
  • AdditionalInfo – Optional. Additional detailed help text can be specified here.
  • DoNotShowUsageDetail – Optional. This flag instructs framework to show or not to show the details in the usage text. By default, it shows details in the usage text. Default value is false.
  • ShowUsageIfEmpty – Optional. This flag instructs the framework to show usage if no arguments passed to the executable at all. Default value is CommandLineParserSettings.ShowUsageIfEmpty value.

5.1.2 ChoCommandLineArgAdditionalUsageAttribute

This attribute is applied to the command line argument class in order to provide very detailed descriptive help text to the them. You may specify them multiple times to the class. These text are displayed at the end of Usage Text seperated by newline.

  • AdditionalUsageText – Required. Detailed descriptive usage text.

5.1.3 ChoCommandLineArgAttribute

This attribute can be applied to the fields and properties of class to designate as switch named command line arguments. This attribute designate the members of the class receive the command line argument value for the specified switch.

5.1.3.1 Descriptive Parameters

There are three descriptive parameters in this attribute.

  • CommandLineSwitch – Required. Command line switch.
  • ShortName – Optional. Short name of the switch, used to produce help text.
  • Description – Optional. Description of the switch, used to produce help text.
  • Aliases – Optional. Specify alternative switches seperated by ‘,’ or ‘;’
  • Order – Optional. Specify the order of the parameters to be validated as well as to be displayed in the usage text.
5.1.3.2 Make argument as required

IsRequired will enforce the command line argument parameter as mandatory parameter. If the value is not specified at the command line argument to the executable for the required option, will throw ChoCommandLineArgException.

5.1.3.3 Provide default value

Providing default value for a command line argument will allow the parser assign this default value to the member when the parameter is not specified at the command line to the executable. Note that setting this parameter does not prevent the user from specifying a different value on the command line, it merely provides the default value should the user opt not to provide one.

5.1.3.4 Providing fallback value

In case the command line argument is passed for the concerned option and failed convert and assign to the member, fallback value is assigned to the member.

5.1.3.5 Specifying Aliases for a command line argument

The Aliases property names the aliases for a command line argument. These are other names with which the command line argument may be referred to. It is a string property, and multiple names can be specified seperated by comma or semi-colon. Any alias specified here must be unique among other aliases and command line switches. Parser will not check for name uniqueness of these options.

5.1.3.6 Formatting parameters

These parameters are optional to be used to formatting and make it to display elegant usage text. Below are the available parameters for use to format the usage text

  • NoOfTabsSwitchDescFormatSeperator – Optional. Number of TAB characters to be placed between switch and description. Default is 1.
  • DescriptionFormatLineSize – Optional. Command line switch description line size. Default is 60.
  • DescriptionFormatLineBreakChar – Optional. Command line switch description line break character. Default is a space (‘ ‘) character.

5.1.4 ChoPositionalCommandLineArgAttribute

This attribute can be applied to the fields and properties of class to designate as positional command line arguments. This attribute designate the members of the class receive the command line argument value for the specified position. Position always starts with 1.

5.1.4.1 Descriptive Parameters

There are three descriptive parameters in this attribute.

  • Position – Required. Command line argument position. Must be value of 1 and above.
  • ShortName – Required. Short name of the switch, used to produce help text.

Besides above descriptive properties, you can specify fallback value, default value, formatting parameters to this argument. Alias can’t specified to this argument.

6. Supported Types

Command Line Argument parser supports all members defined with any CLR datatype. No restriction at all. All the built-in datatypes are automatically managed by parser, no special handling of conversion is required. Below are the supported built-in types are

  • enum
  • bool
  • byte
  • sbyte
  • char
  • decimal
  • double
  • float
  • int
  • uint
  • long
  • ulong
  • short
  • ushort
  • string

If there is an exception occurs during the parser conversion and assignment of the the command line value to a member, it will throw ChoCommandLineArgException.

6.1 Special handling of bool value

This section illustrates about special way of passing and handling bool values from command line arguments. Most of the command line values can be passed to the executable in the below switch:value format

Listing 6.1 Test1.exe with switch and values

>Test1.exe /name:"Raj" /msg:"Hello world"

But bool parameters can be handled in couple of ways

6.1.1 Explicit way

In here the bool values are passed as string value (True/False). This sample illustrates that the switch -r value is passed with True text. Parser takes that value, converts and assign it to the corresponding data member.

Listing 6.2 Test1.exe with explicit bool TRUE value

>Test1.exe /name:"Raj" /msg:"Hello world" /r:True

Listing 6.3 Test1.exe with explicit bool FALSE value

>Test1.exe /name:"Raj" /msg:"Hello world" /r:False

6.1.2 Implicit way

This section illustrates how bool values are set without passing values explicitly. Parser looks for switch presents in the command line arguments for bool parameters. If the bool switch specified (/r), parser takes them as True value. If the bool switch specified as (/r-), parser takes them as False value.

Listing 6.4 Test1.exe with implicit bool TRUE value

>Test1.exe /name:"Raj" /msg:"Hello world" /r

Listing 6.5 Test1.exe with implicit bool FALSE value

>Test1.exe /name:"Raj" /msg:"Hello world" /r-

6.2 Handling of complex datatype members

This section illustrates how to handle complex UDT data type members. There are number of ways to recieve, parse and assign the values to command line argument members.

  • Callback Machanism
  • ValueConverter Mechanism

6.2.1 Callback Machanism

This is easiest way to receive, parse and load the command line argument value to a member. This gives you ultimate control over handling any type of command line argument values in your object. Override OnBeforeCommandLineArgLoaded method in the command line argument object, which will be invoked for each command argument switch by the parser. There you write custom logic for the concerned member and load the member with value. Once you handle the situation, simply return True to tell the parser that you handled the conversion.

Listing 6.4 CommandLineArgObject with Callback override

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
    public string Name;

    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
    public string Message
    {
        get;
        set;
    }

    [ChoCommandLineArg("s", ShortName = "<int | INFINITE>", Description = "Sleep period.")]
    public int Sleep
    {
        get;
        set;
    }

    protected override bool OnBeforeCommandLineArgLoaded(string memberName, ref string value, object defaultValue, object fallbackValue)
    {
        if (memberName == "Sleep")
        {
            if (value == null)
                Sleep = 0;
            else
            {
                if (String.Compare(value.ToString(), "INFINITE", true) == 0)
                    Sleep = -1;
                else
                {
                    int timeout = 0;
                    int.TryParse(value.ToString(), out timeout);
                    Sleep = timeout;
                }
            }
            return true;
        }
        else
            return base.OnBeforeCommandLineArgLoaded(memberName, ref value, defaultValue, fallbackValue);
    }
}

In the sample above, Sleep parameter is int type. But it gives option to take either int or INFINITE value as command line argument. In the callback machanism, we handle it by overriding OnBeforeCommandLineArgLoaded method.

Listing 6.5 Test1.exe with Sleep value passed

>Test1.exe /name:"Raj" /msg:"Hello world" /s:INFINITE

Hello world [Version 1.0.0.0]
Copyright 2014 Cinchoo Inc.

-- ConsoleApplication2.HelloWorldCmdLineParams State --
        Message: Hello world
        Sleep: -1
        Name: Raj

6.2.2 ValueConverter Machanism

This is alternative way to receive, parse and load the command line argument value to a member. This gives you opportunity to perform conversion using ValueConverters. Either you can use existing converters or create new one and use them. In here I’ll show you to how create a new converter and use them in command line argument members. This approach lets you to reuse the conversion logic in a pluggable architecture.

First, lets define a ChoTimeoutConverter. It converts input string value to Timeout (int) value. You can define the converter class derived from either System.Windows.Data.IValueConverter (PresentationFramework.dll) or Cinchoo.Core.IChoValueConverter (Cinchoo.Core.dll). Both interfaces have the same methods. You can use whatever interface suited for your needs.

Listing 6.6 ChoTimeoutConverter class

public class ChoTimeoutConverter : IChoValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return 0;

        int timeout = 0;
        if (String.Compare("INFINITE", value.ToString(), true) == 0)
            return -1;
        else if (int.TryParse(value.ToString(), out timeout))
            return timeout;
        else
            return 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value != null ? value.ToString() : String.Empty;
    }
}

In above, defined ChoTimeoutConverter from IChoValueConverter interface. Implemented the methods. It is self-explanatory.

Now I’ll illustrate how to use the above converter in the command line argument member. Couple of ways you can use them in command line argument object.

  • Defining Converter Attribute and use it
  • Using ChoTypeConverterAttribute directly
6.2.2.1 Defining Converter Attribute and use it

This approach will let you define converter attribute for each converter. In the sample below shows you to define ChoTimeoutConverterAttribute for ChoTimeoutConverter class. The converter attribute must be drived from ChoTypeConverterAttribute class and pass converter type to its converter. See below example

Listing 6.7 ChoTimeoutConverterAttribute class

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public class ChoTimeoutConverterAttribute : ChoTypeConverterAttribute
{
    public ChoTimeoutConverterAttribute()
        : base(typeof(ChoTimeoutConverter1))
    {
    }
}

Once you have attribute defined as above, it can be used against command line argument member to perform conversion of the argument value as below

Listing 6.8 Using ChoTimeoutConverterAttribute in a member

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
    public string Name;

    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
    public string Message
    {
        get;
        set;
    }

    [ChoCommandLineArg("t", ShortName = "<int | INFINITE>", Description = "Timeout period.")]
    [ChoTimeoutConverter]
    public int Timeout
    {
        get;
        set;
    }
}
6.2.2.2 Using ChoTypeConverterAttribute

This illustrates how to use the converter class (ChoTimeoutConverter) directly to the command line object member without defining converter attribute for each converter class. Cinchoo framework provides common attribute class for this purpose. It is ChoTypeConverterAttribute. Simply use this attribute and pass the ChoTimeoutConverter type to its constructor as below.

Listing 6.9 Using ChoTypeConverterAttribute in a member

[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
    [ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
    public string Name;

    [ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
    public string Message
    {
        get;
        set;
    }

    [ChoCommandLineArg("t", ShortName = "<int | INFINITE>", Description = "Timeout period.")]
    [ChoTypeConverter(typeof(ChoTimeoutConverter))]
    public int Timeout
    {
        get;
        set;
    }
}

So far you have learned how to parse, convert and load command line argument value to its members using various methodologies.

6.3 Special handling of Enum

This section illustrates about special way of passing and handling enum values from command line arguments. Most of the command line values can be passed to the executable in the below switch:value format

Listing 6.10 Test1.exe with switch and values

>Test1.exe /name:"Raj" /msg:"Hello world"

Lets begin by defining enum type and command line argument object with enum member as below

public enum Action { ADD, DEL, UPDATE };

[ChoCommandLineArgObject]
public class COMPUTERCmdLineArgObject : ChoCommandLineArgObject
{
 [ChoPositionalCommandLineArg(1, "\\\\computername", IsRequired = true, Order = 0)]
 public string ComputerName;

 [ChoCommandLineArg("action", IsRequired = true)]
 public Action ActionValue;
}

Above code illustrates that Action enum is defined. It is consumed by COMPUTERCmdLineArgObject class by declaring ActionValue member. It must be declared with ChoCommandLineArgAttribute. All enum types must be decorated with ChoCommandLineArgAttribute. 

Below is the test run shows how to pass enum value as command line argument

Listing 6.11 Test1.exe with enum value (Implicit way)

>Test1.exe "\\NYCDR1234234" /UPDATE

It illustrates that the enum values may be passed in /[EnumValue] format.

Listing 6.12 Test1.exe with enum value (Explicit way)

>Test1.exe "\\NYCDR1234234" /action:UPDATE

It illustrates that the enum values may be passed in /Switch:EnumValue format.

7. Customizations

There are ways to customize the parser, like command line switch characters, assignment seperators, usage switches, case sensitive handling of switches etc. The default settings should be good enough for most applications, but they are there for your customizations if you need to.

7.1 Specifying switch characters

This is special character used to prefix with swtiches when you pass command line arguments to the executable. Parser comes with default switch characters ‘/’, ‘-‘. It means that these are the available characters can be prefixed with switches. It can be customizable by opening [appExe].config or App.config file, add or edit custom configuration section ‘commandLineParserSettings’ to it.

Listing 7.1 CommandLineParserSettings config section

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="commandLineParserSettings" type="Cinchoo.Core.Shell.ChoCommandLineParserSettings, Cinchoo.Core" />
    </configSections>
    <commandLineParserSettings switchChars="/, -" valueSeperators = ":, =" />
</configuration>

Cinchoo.Core.Shell.ChoCommandLineParserSettings is the configuration section object. Below are the available parameters for you to customize the parser

  • switchChars – Optional. List of possible command line switch charactors can be specified here. Multiple characters acceptable. Must specify one character. Characters are separated by comma. Default values: “/, -“.
  • valueSeparators – Optional. Specify list of possible switch-value separator characters. Multiple characters can be specified. Must specify atleast one character. Characters are separated by comma. Default values: “:. =”.
  • usageSwitches – Optional. This is the switch used to display usage text. Specify list of possible usage switch strings. Multiple values can be specified. Must specify atleast one value. Strings are separated by comma. Default values: “?, h, help”.
  • fileArgSwitches – Optional. This switch used to specify the file path containing command line arguments. Some programs may have long list of arguments. In order to avoid repeat passing the command line argument values to the executable, you can save them to a file and input the file using this switch. Multiple values can be specified. Must have atleast one value. Characters are seperated by comma. Default values: ‘@’.
  • ignoreCase – Optional. True, command line switches are case insensitive. Otherwise false. Default value: True.
  • showUsageIfEmpty – Optional. True, will show detailed usage text. Otherwise false. Default value: True.
  • doNotShowHeader – Optional. True, will show header information like AssemblyTitle, Version, and Description. Otherwise false. Default value: True.

7.2 Case sensitive of Command Line Switches

You have a option to specify whether the command line switches are case sensitive or not, through ignoreCase parameter in ChoCommandLineParserSettings. Default is that switches are NOT case sensitive.

8. CommandLineObject Overrides

This section illustrates some of the important methods which can be overrideable in order to customize the parser.

8.1 GetUsage() Method

In general, the parser does the quite job of creating the usage text for you in most cases. In rare situation, you may want to customize the way you want the usage text would be. In this case, you can override GetUsage() method. It is a public method, return string value.

8.2 OnBeforeCommandLineArgLoaded Method

This method gets called before each command line argument value is loaded. In this method you have opportunity to validate the command line value, perform conversion or even replace with new value etc. Return true, instruct parser to stop processing of the value. Otherwise continue the process of loading the value.

8.3 OnAfterCommandLineArgLoaded Method

This method gets called for each command line argument is loaded. In here you have option to perform any post assignment tasks like dependent property values can be derived from this property.

8.4 OnCommandLineArgLoadError Method

This method gets called when there is an exception occurs when loading command line argument to a member. In here, you can perform exception handling. Return true, instruct the parser that you handled the exception. Otherwise false.

8.5 OnBeforeCommandLineArgObjectLoaded Method

This method gets called before the command line argument object is loaded. In this method you have opportunity to lookup the payload of the command line arguments overall, perform some pre validation or even replace the values with new ones etc. Return true, instruct parser to stop the parsing. Otherwise continue the process of loading the object.

8.6 OnAfterCommandLineArgLoaded Method

This method gets called after command line argument object is loaded. In here you have option to perform any post assignment tasks like dependent property values can be derived, validation etc.

8.7 OnCommandLineArgObjectLoadError Method

This method gets called when there is an exception occurs when parsing and loading whole command line argument object. In here, you can perform exception handling. Return true, instruct the parser that you handled the exception. Otherwise false.

8.8 OnCommandLineArgNotFound Method

This method gets called when no command line argument found in the argument list to the executable.

9. Advanced Topics

In this topic, I’m going to talk about some of the key advanced topics to understand and use in your projects when you use this parser. It helps you how effective the parser can be utilized in your projects.

9.1 Specifying Argument with Whitespaces

Most of the cases, the command line argument value without any whitespaces can be specified as it is. In case where the value contains white spaces, it must be surrounded by double quotes. For example,

Listing 9.1 Test1.exe with value contains white spaces

>Test1.exe /name:"Raj Nagalngam" /msg:"Hello world" /r:True

9.2 Specifying Quotation Marks into the value

By default double quotes (“) are the only recognized quotation marks. Inside the quotes you may escape quote character itself to insert a literal quotation mark into the value. It can be inserted as below (escaped using additional double quotes)

Listing 9.2 Test1.exe with value contains double quotes

>Test1.exe /name:"Raj""s msg" /msg:"Hello world" /r:True

9.3 Loading arguments from external file

A program may have multiple large, complex sets of command line arguments and wanted to run them multiple times, in this case you can save the values to external file and pass the file to the program. It saves time and effort of retyping the command line argument values for each run.

Listing 9.2 Test1.exe with value contains double quotes

>Test1.exe @"C:\Sample\CmdLineArgs.txt"

10. Validation

In this section, I’ll talk about how to validate each command line argument member values, different approaches of validation methods, etc. Any application that accepts input from command line arguments must ensure that the information is valid in terms of some set of rules that you specify. For example, you may need to check that a customer’s phone number has the correct number of digits, or that a date falls within a particular range. In addition, if the validation fails, you may need to send an error message that explains what is wrong.

Cinchoo provides library of classes, called validators, that supplies the code for validating command line argument members. For example, one validator checks for null strings and another validator checks that a string contains only specific set of characters etc. In some cases, you may want to define your own custom validator and use them to validate the member values.

There are special validaters used to compose, aggregate other validators and group them together in a rule set.

  • ChoAndCompositeValidator – It groups other validators, all validators in this composite validator must be true for a successful validation.
  • ChoOrCompositeValidator – It groups other validators, at least one validators in the composite validator must be true for a successful validation.

If you want to avoid validations using this library feature and take control of validation, you can do so in couple of ways

  • Callback mechanism – OnAfterCommandLineArgLoaded override method can be used to put custom logic to validate the command line argument value.
  • Property Setter mechanism – This is another place where you can do custom validation on these member values.

10.1 Using Validators

The following procedures explains how to use validators in your command line argument object members. There are two ways to use validators for your command line argument members

  • ChoValidatorAttribute – An generic validator attribute, used in case specific validator does not have corresponding attribute.
  • Validator specific attribute – These are customized validator attributes for each validator. For example, ChoStringValidatorAttribute is the attribute for ChoStringValidator class.

Cinchoo supports the following validators out of the box

  • ChoValidators – Validators that Cinchoo library provides itself. You may find number of them under Cinchoo.Core namespace. For example, ChoNotNullValidator, ChoNotNullOrEmptyValidator etc.
  • BCL Configuration Validators – Validators that .NET BCL library provides. You can find them System.Configuration namespace. For example, StringValidator, IntegerValidator etc.
  • BCL DataAnnotation Validators – Another set of validators that .NET BCL library provides under System.ComponentModel.DataAnnotations namespace.

10.1.1 Using ChoValidatorAttribute

This is one way of specifying validation rules to command line argument members. In case where there is no validator attribute available for a specific validator, this attribute is here to rescue. This attribute takes validator type as input. The validator type can be one of below derived classes

  • Cinchoo.Core.ChoValidator – There are number of validators that Cinchoo framework library offers to use in your application.
  • System.Configuration.ConfigurationValidatorBase (System.Configuration.dll) – These set of validators .NET BCL offers to use.

Below are the available optional properties for this attribute

  • ConstructorArgs – Optional. Most of the validators accepts some mandorary parameters through constructor to perform the validation on command line object members. These parameters can be specified through this property. It takes object[] as value. These values are positional constructor arguments.
  • ConstructorArgsText – Optional string value. The constructor arguments can be specified as text and each value is seperated by ‘;’.
  • KeyValuePropertiesText – Optional string value. It is a key value pair seperated by ‘;’ character to set validator property values. For example, “MinValue=1;MaxValue=10”.

Listing 10.1 CommandLine Argument Object with validators

[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
    [ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
    [ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
    public string XmlFilePath
    {
        get;
        set;
    }

    [ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
    [ChoStringValidator(MinLength = 10)]
    [ChoContainsCharactersValidator("A")]
    public string OutputDirectory
    {
        get;
        set;
    }
}

In the sample above, the member ‘XmlFilePath’ is specified with 2 validations. It must be not null and must contain minimum 10 characters. The sample shows how you can use ChoValidatorAttribute to define the validators those dont have corresponding custom validator attributes. Note, multiple validators specified at the top level are combined and validated as AND condition by default. Validation orders are NOT guaranteed sequencial.

‘OutputDirectory’ member is decorated with custom validator attributes correponding to validators. In here, it is decorated with ChoStringValidatorAttribute and ChoContainsCharatersValidatorAttribute. It gives flexibilty, simplicity and type safety in declaring validators.

Create a console application and create an object of ChoAppCmdLineParams as below

Listing 10.2 Main method

class Program
{
    static void Main(string[] args)
    {
        ChoAppCmdLineParams cmdLineParams = new ChoAppCmdLineParams();
        Console.WriteLine(cmdLineParams.ToString());
    }
}

Listed below are test runs of the program with different arguments

Listing 10.3 Test1.exe with no arguments

>Test1.exe
ConsoleApplication2 [Version 1.0.0.0]
Copyright c  2014

Utility to generate schema or class files from given source.

Found exception while loading `xmlfile` command line argument.

The string must be at least 10 characters long.

ConsoleApplication2.exe xmlfile [/o:<string>]

        xmlfile Name of an xml file to infer xsd schema from.
        /o      The output directory to create files in. The default is the
                current directory.

Press any key to continue . . .

In the above run, the executable was run without passing any command line arguments. The application is trying to instantiate the ChoAppCmdLineParams object. While creating such object, the framework tries to validate the member values. In this case, the positional command line argument ‘xmlFilePath’ is failed to validate. The application termintes with exception.

Listing 10.4 Test1.exe with incorrect output directory value

>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"C:\Windows\Systems\Xcpanal.xml"
ConsoleApplication2 [Version 1.0.0.0]
Copyright c  2014

Utility to generate schema or class files from given source.

Found exception while loading `o` command line argument.

The value must contains ALL of the 'A' characters.

ConsoleApplication2.exe xmlfile [/o:<string>]

        xmlfile Name of an xml file to infer xsd schema from.
        /o      The output directory to create files in. The default is the
                current directory.

Press any key to continue . . .

In the above test run, the executable was run with arguments. The positional argument ‘XmlFilePath’ passed the validation (not null AND contains more than 10 characters). But it failed at validating ‘OutputDirectory’. It does not contain character ‘A’ in it. The application terminates with exception.

Listing 10.5 Test1.exe with correct values

>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"C:\Windows\Systems\Acpanal.xml"
ConsoleApplication2 [Version 1.0.0.0]
Copyright c  2014

Utility to generate schema or class files from given source.

-- ConsoleApplication2.ChoAppCmdLineParams1 State --
        XmlFilePath: C:\Windows\Systems\cpanal.xml
        OutputDirectory: C:\Windows\Systems\Acpanal.xml

Press any key to continue . . .

In the above test run, the executable was run with valid arguments. The positional argument ‘XmlFilePath’ as well as ‘OutputDirectory’ passed the validation without any errors.

10.1.2 Using Custom Validator Attributes

Previous section I’ve talked about using generic validator attribute in defining validations on command line argument members. It paves the way to use the validators without validator attributes. Some validators comes with custom validator attributes. It is simple and straight forward to use and type safe. In the sample below, OutoutDirectory member defines 2 validators with its custom attributes.

Listing 10.6 CommandLine Argument Object with validators

[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
    [ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
    [ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
    public string XmlFilePath
    {
        get;
        set;
    }

    [ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
    [ChoStringValidator(MinLength = 10)]
    [ChoContainsCharactersValidator("A")]
    public string OutputDirectory
    {
        get;
        set;
    }
}

10.2 Callback Mechanism

In cases you want to perform some complex validation on members, you can do so with this mechanism. Simply override OnAfterCommandLineArgLoaded method in your command line class as below

Listing 10.6 CommandLine argument object with custom validation

[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams1 : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
    [ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
    [ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
    public string XmlFilePath
    {
        get;
        set;
    }

    [ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
    [ChoStringValidator(MinLength = 10)]
    [ChoContainsCharactersValidator("A")]
    public string OutputDirectory
    {
        get;
        set;
    }

    protected override void OnAfterCommandLineArgLoaded(string memberName, object value)
    {
        if (memberName == "OutputDirectory")
        {
            if (!((string)value).StartsWith(@"C:\"))
                throw new ArgumentException("Invalid directory passed.");
        }
        else
            base.OnAfterCommandLineArgLoaded(memberName, value);
    }
}

In the above sample code shows how to validate members using callback mechanism. If the ‘OutputDirectory’ member value does not starts with ‘C:\’, throws an exception.

Listing 10.7 Test1.exe with incorrect output directory value

>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"D:\Windows\Systems\Xcpanal.xml"
ConsoleApplication2 [Version 1.0.0.0]
Copyright c  2014

Utility to generate schema or class files from given source.

Found exception while loading `o` command line argument.

Invalid directory passed.

ConsoleApplication2.exe xmlfile [/o:<string>]

        xmlfile Name of an xml file to infer xsd schema from.
        /o      The output directory to create files in. The default is the
                current directory.

Press any key to continue . . .

If you run the sample with the above argument values, validation failes for ‘OutputDirectory’ member with exception ‘Invalid directory passed.’.

10.3 Property Setter Mechanism

This is one another way to perform complex validation on members. It is exact similar approach as Callback Machanism. In here the validation can be carried out at the property setter for property command line members. See below sample

Listing 10.8 CommandLine argument object with custom validation

[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams1 : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
    [ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
    [ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
    public string XmlFilePath
    {
        get;
        set;
    }

    private string _outputDirectory;

    [ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
    [ChoStringValidator(MinLength = 10)]
    [ChoContainsCharactersValidator("A")]
    public string OutputDirectory
    {
        get { return _outputDirectory; }
        set
        {
            if (!value.StartsWith(@"C:\"))
                throw new ArgumentException("Invalid directory passed.");

            _outputDirectory = value;
        }
    }
}

In the above sample code shows how to validate members using property setter mechanism. The ‘OutputDirectory’ property validation is handled in property setter. If the value does not starts with ‘C:\’, throws an exception.

Listing 10.9 Test1.exe with incorrect output directory value

>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"D:\Windows\Systems\Xcpanal.xml"
ConsoleApplication2 [Version 1.0.0.0]
Copyright c  2014

Utility to generate schema or class files from given source.

Found exception while loading `o` command line argument.

Invalid directory passed.

ConsoleApplication2.exe xmlfile [/o:<string>]

        xmlfile Name of an xml file to infer xsd schema from.
        /o      The output directory to create files in. The default is the
                current directory.

Press any key to continue . . .

If you run the sample with the above argument values, validation failes for ‘OutputDirectory’ member with exception ‘Invalid directory passed.’.

11. Command Line Object Builder (Grouping)

So far we have learned about defining and consuming individual command line argument object in applications. It best suited for applications with single functionality with the arguments. Some applications performs multiple functions with their own arguments. For example, you have an application which processes data for various input data (network, file, internet etc.) which requires their own respective arguments. It means about having some sort of factory which you can define these contexts with. Basically the first argument would define the context to look up (network, file, internet etc.) then any following arguments would just act as that specific context’s arguments.

‘NET’ dos command is the perfect example of this scenario. If you type ‘net’ produce this

c:\>net
The syntax of this command is:

NET
    [ ACCOUNTS | COMPUTER | CONFIG | CONTINUE | FILE | GROUP | HELP |
      HELPMSG | LOCALGROUP | PAUSE | SESSION | SHARE | START |
      STATISTICS | STOP | TIME | USE | USER | VIEW ]
In the above, ACCOUNTS, COMPUTER, CONFIG etc. are contexts to ‘NET’ command. Each takes their own set of arguments. If you want to see the arguments of ACCOUNTS context, type ‘net ACCOUNTS /?’ as below
c:\>net ACCOUNTS /?
The syntax of this command is:

NET ACCOUNTS
[/FORCELOGOFF:{minutes | NO}] [/MINPWLEN:length]
              [/MAXPWAGE:{days | UNLIMITED}] [/MINPWAGE:days]
              [/UNIQUEPW:number] [/DOMAIN]
Here I’m going to walk you through mimicing ‘NET’ command with START, COMPUTER, STOP contexts only using Cinchoo library. First define a Command Line Object Builder object as below

11.1 Defining Command Line Argument Builder

First define command line object builder as below

Listing 11.1 Command line argument builder object

[ChoCommandLineArgBuilder]
public class NetCmdBuilder : ChoCommandLineArgBuilder
{
    [ChoCommandLineArgBuilderCommand("START", typeof(STARTCmdLineArgObject), Order = 0)]
    [ChoCommandLineArgBuilderCommand("STOP", typeof(STOPCmdLineArgObject), Order = 1)]
    [ChoCommandLineArgBuilderCommand("COMPUTER", typeof(COMPUTERCmdLineArgObject), Order = -1)]
    public NetCmdBuilder()
    {
    }
}

The code above illustrates about defining command line object builder object. First thing define a builder class (ex. NetCmdBuilder) from ChoCommandLineArgBuilder class, it indicates that this object is a command line argument builder object. And it must be decorated with ChoCommandLineArgBuilderAttribute to complete the definition. Besides that, we need to start defining commands mapping using ChoCommandLineArgBuilderCommandAttribute in the default constructor of the builder. In the above example, the builder defined with 3 commands START, STOP and COMPUTER mapped with STARTCmdLineArgObject, STOPCmdLineArgObject and COMPUTERCmdLineArgObject respectively. The order in the attribute describes about the display order of the commands in the usage text.

Listing 11.2 COMPUTERCmdLineArgObject

public enum Action { ADD, DEL };

[ChoCommandLineArgObject(DoNotShowUsageDetail = true)]
public class COMPUTERCmdLineArgObject : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "\\\\computername", IsRequired = true, Order = 0)]
    public string ComputerName;

    [ChoCommandLineArg("action", IsRequired = true)]
    public Action Action;
}

The above command line argument contains two members, ComputerName – positional required argument and Action – an required enum argument. Note, DoNotShowUsageDetail is true tells the framework not to show the details of each member argument in the usage text.

Listing 11.3 STARTCmdLineArgObject

[ChoCommandLineArgObject]
public class STARTCmdLineArgObject : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "service")]
    public string ServiceName;
}

Listing 11.4 STOPCmdLineArgObject

[ChoCommandLineArgObject(DoNotShowUsageDetail = true)]
public class STOPCmdLineArgObject : ChoCommandLineArgObject
{
    [ChoPositionalCommandLineArg(1, "service", IsRequired = true)]
    public string ServiceName;
}

Listing 11.5 Main Method

class Program
{
    static void Main(string[] args)
    {
        NetCmdBuilder netCmdBuilder = new NetCmdBuilder();
        Console.WriteLine(netCmdBuilder.CommandLineArgObject.ToString());
    }
}

Lets start by creating new instance of netCmdBuilder object. Thats all. The framework does the major lifting of the work behind the scene. After successful load of the arguments, CommandLineArgObject member of the builder object is loaded with matched command object based on the context passed to the executable as argument.

Listed below are test runs of the programs with different set of arguments and its output.

Listing 11.6 net.exe with no arguments

c:\>net

The syntax of this command is:

NET [COMPUTER | START | STOP]

Press any key to continue . . .

Listing 11.7 net.exe with COMPUTER context, no computername passed

c:\>net COMPUTER

Missing '\\computername' argument.

NET COMPUTER \\computername {/ADD | /DEL}
Press any key to continue . . .

Listing 11.7 net.exe with COMPUTER context with valid arguments

c:\>net COMPUTER \\NYC123453 /DEL

-- CommadLineObjectBuilderSample.COMPUTERCmdLineArgObject State --
        ComputerName: \\NYC123453
        Action: DEL

Press any key to continue . . .

In the above sample successful run, netCmdBuilder.CommandLineArgObject is populated with instance of COMPUTERCmdLineArgObject object.

11.2 Attributes

11.2.1 ChoCommandLineArgObjectAttribute

This attribute is applied to the class which will construct the command line argument object for the passed context and load with them the command line arguments. It contains same set of properties as ChoCommandLineArgObjectAttribute. Please refer the section.

11.2.2 ChoCommandLineArgBuilderCommandAttribute

This attribute is applied to the constructor of the builder class to define the mapping of the commands with command line argument classes. Multiple attributes may be used to define the mapping.

Listing 11.8 Sample command line builder object

[ChoCommandLineArgBuilder]
public class NetCmdBuilder : ChoCommandLineArgBuilder
{
    [ChoCommandLineArgBuilderCommand("START", typeof(STARTCmdLineArgObject), Order = 0)]
    [ChoCommandLineArgBuilderCommand("STOP", typeof(STOPCmdLineArgObject), Order = 1)]
    [ChoCommandLineArgBuilderCommand("COMPUTER", typeof(COMPUTERCmdLineArgObject), Order = -1)]
    public NetCmdBuilder()
    {
    }
}

The above code illustrates that the constructor defined with three commands using ChoCommandLineArgBuildCommandAttribute.

  • Command – Required. Command name.
  • CommandType – Required. A command line argument object type.
  • Order – Optional order to display the commands in the usage text.

11.3 Overrrides

11.2.2 GetCommandLineArgObjectType()

This method can be overridden to take control of discovering the command type for the passed command. Usually all the mapping is done using ChoCommandLineArgBuildCommandAttribute in the builder class. Occationally you may want avoid doing so by overriding this method to handle it.

[ChoCommandLineArgBuilder]
public class ChoNETCommandLineArgBuilder : ChoCommandLineArgBuilder
{
    [ChoCommandLineArgBuilderCommand("ACCOUNTS", typeof(ChoAppCmdLineParams))]
    public ChoNETCommandLineArgBuilder()
    {
    }

    public override Type GetCommandLineArgObjectType(string command)
    {
        if (command == "COMPUTER")
            return typeof(COMPUTERCmdLineArgObject);
        else
            return base.GetCommandLineArgObjectType(command);
    }
}

The above code illustrates how to override GetCommandLineArgObjectType method.

Cinchoo – Read from console with timeout

You have a console application in which you want to give the user number of seconds to respond to the prompt. If no input is made after a certain period of time, program should continue.

Cinchoo framework provides this through ChoConsole class.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core.Shell.Console

Below are the following methods

Read() Overloads:

This method reads the next character from the standard input stream either within the specified timeout period or infinity.

public static int Read(int timeoutInMilliSeconds);
public static int Read(int timeoutInMilliSeconds, int? defaultValue);
public static int Read(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

ReadLine() Overloads:

This method reads the next line of characters from the standard input stream either within the specified timeout period or infinity.

public static int ReadLine(int timeoutInMilliSeconds);
public static int ReadLine(int timeoutInMilliSeconds, int? defaultValue);
public static int ReadLine(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

ReadKey() Overloads:

This method reads the next character from the standard input stream either within the specified timeout period or infinity.

public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds);
public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds, int? defaultValue);
public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

Cinchoo – ChoConsolePercentageProgressorEx

Cinchoo framework provides another elegant console progress bar indicator to perform lengthy operation in the console application. The feature is very useful when you want to give a visual indicator of how a task is performing.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core.Shell.Console

Below is the sample code

using (ChoConsolePercentageProgressorEx cp = new ChoConsolePercentageProgressorEx("Calculating..."))
{
    cp.ErrorOccured += (sender, eventArg) => cp.Write(eventArg.Exception.Message);

    cp.Start((sender, runningPercentage, state) =>
    {
        Thread.Sleep(1000);
        if (runningPercentage == cp.MinPercentage)
            return new Tuple<int, string>(10, "Step 1 - Status Msg");

        switch (runningPercentage)
        {
            case 10:
                //Do the custom operation here
                return new Tuple<int, string>(25, "Step 2 - Status Msg");
            case 25:
                //Do the custom operation here
                return new Tuple<int, string>(90, "Step 3 - Status Msg");
            default:
                //Do the custom operation here
                return new Tuple<int, string>(cp.MaxPercentage, "Complete");
        }
    }
    );
}

When you run the above code, you can see the below output

For any exception occurred during the operation, can be captured by subscribing to ErrorOccured event.

cp.ErrorOccured += (sender, eventArg) => Console.WriteLine(eventArg.Exception.ToString());

The custom operation can be terminated in couple of ways

1. Stop() – Graceful termination

2. Abort() – Abnormal termination

Happy coding!!!

Cinchoo – ChoConsoleSpinProgressor

Using Cinchoo framework, you can perform lengthy operation with the spin progress indicator in the console window. The feature is very useful when you want to give a visual indicator of how a task is performing.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core.Shell.Console

Below is the sample code

int x = 0;
using (ChoConsoleSpinProgressor cp = new ChoConsoleSpinProgressor("Calculating...", ConsoleColor.Red))
{
    cp.ErrorOccured += (sender, eventArg) => cp.Write(eventArg.Exception.Message);
    cp.Start((sender, state) =>
        {
            cp.ConsoleSession.WriteLine("Processing Step" + x++);
            Thread.Sleep(1000);

            if (x > 5)
                return false; //To indicate the completion of the operation
            else
                return true; //To indicate continuation of the operation
        }
    );
}

When you run the above code, you can see the below output

For any exception occurred during the operation, can be captured by subscribing to ErrorOccured event.

cp.ErrorOccured += (sender, eventArg) => ((ChoConsoleSpinProgressor)sender).Write(eventArg.Exception.Message);

The custom operation can be terminated in couple of ways

1. Stop() – Graceful termination

2. Abort() – Abnormal termination

Happy coding!!!

Cinchoo – ChoConsolePercentageProgressor

Using Cinchoo framework, you can perform lengthy operation with the percentage progress indicator in the console window. The feature is very useful when you want to give a visual indicator of how a task is performing.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core.Shell.Console

Below is the sample code

using (ChoConsolePercentageProgressor cp = new ChoConsolePercentageProgressor("Calculating...", ConsoleColor.Green))
{
    cp.ErrorOccured += (sender, eventArg) => cp.Write(eventArg.Exception.Message);

    cp.Start((sender, runningPercentage, state) =>
        {
            cp.Write("Completed: " + runningPercentage);
            switch (runningPercentage)
            {
                case 0:
                    //Do the custom operation here
                    return 10;
                case 10:
                    //Do the custom operation here
                    return 25;
                case 25:
                    //Do the custom operation here
                    return 90;
                default:
                    //Do the custom operation here
                    return cp.MaxPercentage;
            }
        }
    );
}

When you run the above code, you can see the below output

For any exception occurred during the operation, can be captured by subscribing to ErrorOccured event.

cp.ErrorOccured += (sender, eventArg) => ((ChoConsolePercentageProgressor)sender).Write(eventArg.Exception.Message);

The custom operation can be terminated in couple of ways

1. Stop() – Graceful termination

2. Abort() – Abnormal termination

Happy coding!!!

Cinchoo – Read password from console

Introduction

Cinchoo is the application framework for .NET. It largely includes large class libraries and provides many features like Configuration Management, Generic Application Host, CommandLine argument parser, useful utility classes etc.

In this article, I’m going to talk about reading password from console. Rarely we do develop console applications that would take inputs from console window. In some situations you may want to accept some secure inputs from console window. Cinchoo library provides a API to take such input from console.

Download the Latest Cinchoo Binary here. (Nuget Command: Install-Package Cinchoo)

Using the code

Cinchoo exposes couple of API methods to read password or secure input from console window, It is exposed in ChoConsole class under Cinchoo.Core.Shell namespace

public static SecureString ReadSecurePassword(char maskChar = '*', int maxLength = Int32.MaxValue, Func<char, bool> filter = null, int timeoutInMilliSeconds = -1)

public static string ReadPassword(char maskChar = '*', int maxLength = Int32.MaxValue, Func<char, bool> filter = null, int timeoutInMilliSeconds = -1)

where

  • maskChar – Masked character.
  • maxLength – Maximum number of characters the user can type in.
  • filter – Optional callback method to filter any characters from accepting in the password.
  • timeoutInMilliSeconds – The number of milliseconds to wait before the method times out.

First method, returns SecureString, It represents text that should be kept confidential, such as by deleting it from computer memory when no longer needed. Most of .NET api not accepting SecureString as passwords. This method is recommended.

Second method, simply returns the password as string object. It is claimed to be insecure to keep the password in standard string object.

Sample #1

Below sample, read the password from console as string object with ‘*’ as masked character, maxlength of 10 chars. Besides it limits the password from accepting ‘A’ or ‘R’ characters.

class Program
{
    static void Main(string[] args)
    {
        //Read password from console as string
        Console.WriteLine(ChoConsole.ReadPassword('*', 10, (c) => c == 'A' || c == 'R'));
    }
}

Sample #2

Below sample, read the password from console as SecureString object with ‘^’ as masked character, maxlength of 10 chars. Besides it limits the password from accepting ‘A’ or ‘R’ characters with the timeout of 5 secs.

class Program
{
    static void Main(string[] args)
    { 
        //Read password from console as SecureString
        SecureString x = ChoConsole.ReadSecurePassword('^', 10, (c) => c == 'A' || c == 'R', 5000);

        //For testing purpose, I'm using this utility class to reveal the content of the SecureString. 
        //In real-world, you should avoid it.
        ChoInsecureString z = new ChoInsecureString(x);
        foreach (var c in z)
            Console.Write(c);
    }
}

Cinchoo – ChoConsole, Part 1

Cinchoo framework provides one another helper class, ChoConsole. It is a static class, exposes lot of methods to help to build Console application.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core.Shell.Console

Below are the following methods

Write() Overloads:

This class provides various Write methods to write values to application console window. Here I’m going to walk over one set of Write methods,

public static void Write(string msg);
public static void Write(string msg, ConsoleColor foregroundColor);
public static void Write(string msg, ConsoleColor foregroundColor, ConsoleColor backgroundColor);
public static void Write(string msg, ChoPoint cursorLocation);
public static void Write(string msg, ChoPoint cursorLocation, ConsoleColor foregroundColor, ConsoleColor backgroundColor);
public static void Write(string msg, int cursorLeft, int cursorTop);
public static void Write(string msg, int cursorLeft, int cursorTop, ConsoleColor foregroundColor, ConsoleColor backgroundColor);

There are number other Write overloads to handle other datatype variables (int, long, char etc). Please explore yourself.

WriteLine() Overloads:

This class provides various WriteLine methods to write values followed by NewLine to application console window. Here I’m going to walk over one set of WriteLine methods,

public static void WriteLine(string msg);
public static void WriteLine(string msg, ConsoleColor foregroundColor);
public static void WriteLine(string msg, ConsoleColor foregroundColor, ConsoleColor backgroundColor);
public static void WriteLine(string msg, ChoPoint cursorLocation);
public static void WriteLine(string msg, ChoPoint cursorLocation, ConsoleColor foregroundColor, ConsoleColor backgroundColor);
public static void WriteLine(string msg, int cursorLeft, int cursorTop);
public static void WriteLine(string msg, int cursorLeft, int cursorTop, ConsoleColor foregroundColor, ConsoleColor backgroundColor);

There are number other WriteLine overloads to handle other datatype variables (int, long, char etc). Please explore yourself.

Pause() Overloads:

This method writes the default/specified string value to the standard output stream. Reads the next character from the standard input stream.

public static void Pause();
public static void Pause(string msg);

PauseLine() Overloads:

This method writes the default/specified string value, followed by the current line terminator,  to the standard output stream. Reads the next character from the standard input stream.

public static void PauseLine();
public static void PauseLine(string msg);

Read() Overloads:

This method reads the next character from the standard input stream either within the specified timeout period or infinity.

public static int Read();
public static int Read(int timeoutInMilliSeconds);
public static int Read(int timeoutInMilliSeconds, int? defaultValue);
public static int Read(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

ReadLine() Overloads:

This method reads the next line of characters from the standard input stream either within the specified timeout period or infinity.

public static int ReadLine();
public static int ReadLine(int timeoutInMilliSeconds);
public static int ReadLine(int timeoutInMilliSeconds, int? defaultValue);
public static int ReadLine(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

ReadKey() Overloads:

This method reads the next character from the standard input stream either within the specified timeout period or infinity.

public static ConsoleKeyInfo ReadKey();
public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds);
public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds, int? defaultValue);
public static ConsoleKeyInfo ReadKey(int timeoutInMilliSeconds, int? defaultValue, string errMsg)

ReadPassword() Overloads:

This method reads the next line of characters from the standard input stream. Typed characters will be masked with maskChar in the console window.

public static string ReadPassword();
public static string ReadPassword(int maxLength);
public static string ReadPassword(char maskChar, int maxLength);

Happy coding!!!

Cinchoo – Command Line Argument Parser, Part 14

Inside Command Line Argument Parser – Automatic Help

Another feature that Cinchoo framework provides you is that, it automatically creates Usage help text.

1. Add a reference to Cinchoo.Core.dll

2. Namespace: Cinchoo.Core.Shell

For a sample Command Line object below,

[ChoCommandLineArgObject(ApplicationName = "Hello World", Copyright = "Copyright (c) Cinchoo Inc.")]
public class MyCommandLineArgObject : ChoCommandLineArgObject
{
    [ChoCommandLineArg("D", DefaultValue = "%NOW%", Description = "Business Date.", ShortName = "Today")]
    public DateTime Today
    {
        get;
        set;
    }

    [ChoCommandLineArg("N", DefaultValue = "{100+100}", Description = "No of spaces for a TAB.")]
    public int Count
    {
        get;
        set;
    }

    [ChoCommandLineArg("I", DefaultValue = false, FallbackValue = true, Description = "Include Sub directory.")]
    public bool IncludeSubDir
    {
        get;
        set;
    }

    [ChoCommandLineArg("O", IsRequired = true, Description = "Output Directory.")]
    public string OutFolder
    {
        get;
        set;
    }
}

If the application containing above type executed with the below command line arguments

/help or /? or /h

When creating instance of MyCommandLineArgObject as below,

MyCommandLineArgObject commandLineArgObject = new MyCommandLineArgObject();
Console.WriteLine(commandLineArgObject.ToString());

And run the application, the commandLineArgObject will display the usage as below

Hello World [Version 1.0.0.0]
Copyright (c) Cinchoo Inc.

Cinchoo.Core.CommandLineArgs.Test.exe -D:Today -N:<int> -I:{True|False} -O:[<string>]

Where
        -D      Business Date.
        -N      No of spaces for a TAB.
        -I      Include Sub directory.
        -O      Output Directory.