Skip to content

Argument definition basics

Giuseppe Cramarossa edited this page Dec 15, 2023 · 3 revisions

In the previous section you have seen how to define and manage commands using the InterAppConnector library. If you haven't read it or you don't know how to creae a command, it is strongly suggested that you start from Command basics

In this section, you will learn how to declare arguments and parameters in a command. In particular, you will learn:

  • argument declaration
  • mandatory and optional arguments
  • define arguments in a command
  • an example that shows how to define mandatory and optional arguments

Argument declaration

InterAppConnector uses the public properties defined in an object in order to know the name and the type of the arguments. This means that if you want to declare an argument called age that accepts only positive numbers, you have to declare a public uint property in your class as described below

public uint Age {get; set;}

When a value is assegned to this argument (for example via command line), the library will check if it matches the type defined for the property and set the desired value to the property.

Normally, argument names are case insensitive. This means that if you write age, Age or AGE as argument, the value will be assigned always to the Age property.

In some special cases (for instance in code obfuscation) you may need to change this behaviour. For further information, see the Advanced section

Mandatory and optional arguments

InterAppConnector supports mandatory and optional arguments, and in particular will check if mandatory ones are set before executing the commands.

The Age property defined in the example above is a mandatory argument. If you want to define an optional argument, you have to declare a nullable property or use its syntactic sugar form with the question mark. An example of optional parameter is

public bool? ForceDeletion {get; set;}

If mandatory parameters are missing in command line applications, InterAppConnector will write an error message in console application indicating the missing arguments and a description of the arguments that can be defined for that action.

A typical message looks like this

[02/07/2023 18:37:24] ERROR (3) : Cannot execute the selected action because some mandatory parameters are missing. Missing parameters: filepath
- info
  Gets some info regarding the file
        -filepath (required) : Define the file path
        -outputformat (optional) : Define the output format
        Accepted values for this parameter:
                json (0) : Json format is used by applications in order to exchange messages and status
                text (1) : Text format is used in order to give messages to the user

The execution in a batch application raises a MissingMandatoryArgumentException exception. It is strongly suggested that you catch this error in your code in order to write resilient and robust code.

Regarding optional arguments, InterAppConnector will check only if the value assigned to the argument matches the type defined in the property, if set, otherwise no values will be set in the corresponding properties.

It is strongly suggested that you check if properties related to optional arguments have a value set. For instance, assuming that you have the ForceDeletion property defined above, you can write these lines of code

if (arguments.ForceDeletion.HasValue)
{
  // the forcedeletion argument has been set by the user. Force the deletion
}
else
{
  // the forcedeletion argument has not been set by the user.
}

Define arguments in commands

In order to define multiple arguments in a command, it is suggested that you create a dedicated class with the arguments you want to use in your command. This approach will help you to keep your code cleaner and easy to maintain in case you need to add other arguments. For instance, assuming that you need to declare the two argments described above (forcedeletion and age), you can add in your project a class written in this way

public class Argument 
{
  public uint Age {get; set;}
  public bool? ForceDeletion {get; set;}
}

Then, create a new file that contains a new class that inherit the ICommand<> interface, define the class that contains the arguments you want to use in your commands (in this case Argument) and implement the method of the interface

public class MyAwesomeCommand : ICommand<Argument> 
{
  public string Main(Argument arguments)
  {
    // write your code here
  }
}

It is possible to define arguments that are shared between different commands. For further information, see the page Shared arguments between different commands

Example

In this example, you are creating a simple file reader console application that reads the content of the file if exists, otherwise returns a custom error message

For this example you are using Visual Studio 2022 and you are creating:

  • A project library that contains the commands and a file containing the arguments necessary to run the application
  • A console application that will be used to call the command via cli

For this example it is assumed that you have learned what is a command and how to implement it

Follow these steps to complete this example:

  1. Open Visual Studio, create a blank solution and name it FileReaderApplication. Choose the language version (.NET 6 or above) and choose a location for your solution (for example C:\SampleProjects)

  2. Create a new library project and call it FileReaderApplication.Library. Then follow the steps below to complete the class library

    1. Add the InterAppConnector library as project reference

    2. Add a file to the project and call it FileReaderDataModel.cs

    3. Replace the content of FileReaderDataModel.cs with the code below

      namespace FileReaderApplication.Library
      {
          public class FileReaderDataModel
          {
              public string FileLocation { get; set; } = string.Empty;
              public uint? LineNumbers { get; set; }
          }
      }
    4. Rename Class1.cs to ReadCommand.cs

    5. Replace the content of ReadCommand.cs with the code below

      using InterAppConnector;
      using InterAppConnector.Attributes;
      using InterAppConnector.DataModels;
      using InterAppConnector.Interfaces;
      
      namespace FileReaderApplication.Library
      {
          [Command("read", Description = "Read the content of the file")]
          public class ReadCommand : ICommand<FileReaderDataModel>
          {
              public string Main(FileReaderDataModel arguments)
              {
                  CommandOutput.Info("Checking if the file " + arguments.FileLocation + " exists");
                  string output;
                  if (File.Exists(arguments.FileLocation))
                  {
                      string fileContent = File.ReadAllText(arguments.FileLocation);
                      List<string> lines = new List<string>(fileContent.Split(Environment.NewLine));
                      CommandOutput.Info("File exists. Total line numbers: " + lines.Count);
                      CommandOutput.Info("Checking if the linenumbers argument is set");
                      if (arguments.LineNumbers.HasValue)
                      {
                          CommandOutput.Info("linenumbers set. The value is " + arguments.LineNumbers.Value);
                          if (arguments.LineNumbers.Value > lines.Count)
                          {
                              CommandOutput.Info("The value set to line numbers is greater than the number of lines contained in the file. Reading the entire file");
                              output = CommandOutput.Ok(fileContent);
                          }
                          else
                          {
                              CommandOutput.Info("Reading the first " + arguments.LineNumbers.Value + " lines of the file");
                              output = CommandOutput.Ok(string.Join(Environment.NewLine, lines.GetRange(0, (int)arguments.LineNumbers.Value)));
                          }
                      }
                      else
                      {
                          CommandOutput.Info("linenumbers is not set. Reading the entire file");
                          output = CommandOutput.Ok(fileContent);
                      }
                  }
                  else
                  {
                      output = CommandOutput.Error("Cannot read the content of the file in " + arguments.FileLocation + ". File is not accessible or does not exist");
                  }
      
                  return output;
              }
          }
      }
  3. Create a new console application project and name it FileReaderApplication.CLI. Then follow the steps below to complete the console application:

    1. Add the InterAppConnector library as project reference

    2. Add the FileReaderApplication.Library project as project reference

    3. Replace the content of Program.cs with the code below (CommandManager and InterAppConnector are explained in detail in Integration with console applications page)

      using InterAppConnector;
      using FileReaderApplication.Library;
      using InterAppConnector.DataModels;
      using InterAppConnector.Enumerations;
      
      namespace FileReaderApplication.CLI
      {
          public class Program
          {
              static void Main(string[] args)
              {
                  CommandManager command = new CommandManager();
                  command.AddCommand<ReadCommand, FileReaderDataModel>();
      
                  InterAppCommunication connector = new InterAppCommunication(command);
                  connector.ErrorMessageEmitted += Connector_ErrorMessageEmitted;
                  connector.ExecuteAsInteractiveCLI(args);
              }
      
              private static void Connector_ErrorMessageEmitted(CommandExecutionMessageType messageStatus, int exitCode, object message)
              {
                  Console.WriteLine("This is a custom error that replaces the standard one");
              }
          }
      }
  4. Build the solution (you can leave the debug mode if you want)

  5. Open the Command Prompt and go to the location of the executable. For instance, if you have placed your solution in C:\SampleProjects you can go to the executable by typing the above command

    cd C:\SampleProjects\FileReaderApplication\FileReaderApplication.CLI\bin\Debug\net6.0
  6. Type the executable name with the extension (for instance FileReaderApplication.CLI.exe). You should see an output similar to the one below

    ----------------------------------------------------------------------------------
    
    FileReaderApplication.CLI 1.0.0.0
    
    ----------------------------------------------------------------------------------
    
    Available actions:
    
    - read
    Read the content of the file
            -filelocation (required) : No description provided
            -linenumbers (optional) : No description provided
  7. Type the executable name with the extension (for instance ReadCommand.CLI.exe) followed by the verb read. You should see an output similar to the one below

    [07/08/2023 12:17:26] ERROR (3) : Cannot execute the selected action because some mandatory parameters are missing. Missing parameters: filelocation
    - read
    Read the content of the file
            -filelocation (required) : No description provided
            -linenumbers (optional) : No description provided
  8. Create the file testfile.txt in the same directory of the executable

  9. Write a string in the file created at step 8, for example "Text in line 1"

  10. Retype the command described at step 7 and add -filelocation .\testfile.txt. You should see an output similar to the one below

    [11/10/2023 23:50:34] INFO (2) : Checking if the file .\testfile.txt exists
    [11/10/2023 23:50:34] INFO (2) : File exists. Total line numbers: 1
    [11/10/2023 23:50:34] INFO (2) : Checking if the linenumbers argument is set
    [11/10/2023 23:50:34] INFO (2) : linenumbers is not set. Reading the entire file
    [11/10/2023 23:50:34] SUCCESS (0) : Text in line 1
  11. Append 4 new lines in the file created at step 8, and write in each line a new string, for example "Text in line x", where x is the line number. The edited file should contain now these lines.

    Text in line 1
    Text in line 2
    Text in line 3
    Text in line 4
    Text in line 5
  12. Retype the command described at step 10. You should see an output similar to the one below

    [11/10/2023 23:50:34] INFO (2) : Checking if the file .\testfile.txt exists
    [11/10/2023 23:50:34] INFO (2) : File exists. Total line numbers: 5
    [11/10/2023 23:50:34] INFO (2) : Checking if the linenumbers argument is set
    [11/10/2023 23:50:34] INFO (2) : linenumbers is not set. Reading the entire file
    [11/10/2023 23:50:34] SUCCESS (0) : Text in line 1
    Text in line 2
    Text in line 3
    Text in line 4
    Text in line 5
  13. Now let's use the optional parameter without a wrong value. Retype the command described at step 10 and add -linenumbers five. You should see an output like the one below

    [11/10/2023 23:50:34] ERROR (3) : The value provided to argument linenumbers is not acceptable. Please provide a valid value (Parameter 'linenumbers')
  14. Let's try to use the same command written in line 13 without a value passed to -linenumbers. You should see an output like the one below

    [11/10/2023 23:50:34] ERROR (3) : The value provided to argument linenumbers is not acceptable. Please provide a valid value (Parameter 'linenumbers')
  15. Now let's use the optional parameter with a correct value. Retype the command described at step 10 and add -linenumbers 3. You should see an output like the one below

    [11/10/2023 23:50:34] INFO (2) : Checking if the file .\testfile.txt exists
    [11/10/2023 23:50:34] INFO (2) : File exists. Total line numbers: 5
    [11/10/2023 23:50:34] INFO (2) : Checking if the linenumbers argument is set
    [11/10/2023 23:50:34] INFO (2) : linenumbers set. The value is 3
    [11/10/2023 23:50:34] INFO (2) : Reading the first 3 lines of the file
    [11/10/2023 23:50:34] SUCCESS (0) : Text in line 1
    Text in line 2
    Text in line 3