When operating the System there are a number of tasks/functions such as data import/data export or batch report generation, which must be performed in an automatic, batch mode, perhaps, according to a schedule. Interaction with the user in such cases is minimal or non-existent.

It may be impractical or even impossible to use for this purpose a heavy, full-featured Win or Web application with its powerful graphical interface as this application loads dozens of different modules during the initialization. Many of these loadable modules may be not necessary for a particular purpose.

For this class of tasks, it would be much better to use a lightweight console application to which only a set of modules that are required to solve the given problem is connected. The parameters required for a specific task may be passed on the command line.

At the moment, there is no way to create a lightweight version of the XAF application that would implement a simple mechanism for performing the required functions of XAF modules with the opportunity to run in a console mode.

To resolve the problems, you should:

  1. Implement lightweight console applications on XAFARI platform (applications which support all necessary infrastructure of Xafari applications, including the availability of the model and the database). Moreover, these applications do not require a graphical user interface, which in turn would help to avoid loading and initializing of the GUI components.
  2. Implement the infrastructure, which enables to describe the function (command) of any XAF module in a uniform way.
  3. Create a command-line utility that allows executing the commands given by arbitrary user-defined XAF modules.
  4. As a part of the utility, implement flexible adjustment mechanisms of the authentication subsystem.

Description of project solutions

Console applications on Xafari platform

Using XafApplication class as a base class, we have created class Xafari.WouiApplication (without user interface). An abstract CreateLayoutManagerCore method of the base class has been implemented in it. Methods which provide the authentication (Logon, Logoff) have also been implemented.

At this stage, Xafari.ConsoleApplication class does not contain any implementation and it is absolutely declarative.

This class is used in the development of the console application, by analogy with the WinApplication class: the Xafari.ConsoleApplication implements a derived class whose instance is created and initialized for example in the Main method.

Declaration of commands to be performed by the module

Developers implement commands by enclosing them in the XAF module. To use commands infrastructure in the module, the developer must add the assembly to the module, connect Xafari assembly to the module, as well as name space Xafari.Commands, which contains the required classes and interfaces. The figure below shows a diagram of the classes included in the assembly:

[image width="100%" src="https://galaktikasoft.com/xafari/wp-content/uploads/sites/3/2014/11/Xafari-Commands.png" alt="The class diagram of Xafari.Commands." style="style-2" position="below" lightbox="1"] If you want to make the commands from the module become "visible" by the Run Commands Utility, the Command Module Class (ModuleBase derived class) should implement the ICommandEnumerator interface. The interface describes the only enumerated type property field - Commands. It can be implemented on the basis of the iterator block, as in Code Snippet 1 below.
Code Snippet 1. Implementation of the property ICommandEnumerator.Commands.

Each command is described by a separate class. This class must implement the ICommand or ICommandExtIO interfaces. The Description property should provide the description of the command that the user will see when he calls for help on the pitch. The Name property must provide the name of the command. The name should be short and without spaces.

With this convention, it becomes easier to use it when specifying a command, for example, as a command line parameter. The ParametersDescription property must provide a collection of elements of CommandParameterDescription type– the description of command options. The Out property with the TextWriter type is used for displaying the text data by the command implementation code during its execution. This property is initialized by the method which runs the command and the developer does not have to worry about its initialization. It is only necessary to take into consideration that when you execute the command, it may occur that the property is not be initialized (the caller did not want to receive the output of).

And finally, the code directly performing useful work, ie, a command execution, must be implemented in Execute method which gets a collection of key-value pairs representing the command parameters, as well as a reference link to a copy of XAF application that caused the command to execute.

ICommandExtIO interface extends ICommand, adding two new properties - Error and In. The Error property, having the TextWriter type, is designed to display error messages that occur during the execution of the command. The property In with the type TextReader can be used, if necessary, to read the data required by the command. For example, in a console utility for running commands, this property is bound to the standard input stream Console.In. In this case, the implementation of the command can read the data from the redirected input stream of the command line, for example, such as:

To simplify the task for the commands developer, abstract classes CommandBase and CommandExtIOBase have been implemented. They contain a code that can be used to implement many commands. There is a virtual method ValidateParameters, performing the basic validation of the parameters. If an invalid parameter is detected, an exception of type ArgumentException is generated.

This method considers all the parameters optional. If necessary, the developer can complement parameter validation by overriding the method. When implementing additional validation of the parameters by the developer, in the case of the detection of invalid settings, it is also necessary to generate an exception of type ArgumentException or its derived class.

Properties Out, Error, In have been implemented so that in the instruction code the developer does not have to worry about the fact that these properties were not be initialized when the command is invoked. For these purposes, objects - "Blank" are used as the default values for these properties. They do not do anything by themselves but allow the developer to avoid checkings for null properties every time you need to perform output.

The code of command implementation when using these abstract classes is located in the abstract method ExecuteCore.
If the commands developer introduces additional checks parameters in the implementation of the command in ExecuteCore method, in the case of the detection of invalid settings, it is also necessary to generate an exception of only the above types or their derived classes.

Utility for running commands provided by command modules

The utility must be configured individually to the needs of a particular application. The configuration is done via the standard configuration file RunCmd.exe.config.

The setting of the security subsystem is performed in the section. The utility must support the same authentication mechanism as the main application to which the utility is provided and with whose database the commands interact. Applications can use different authentication mechanisms.

For example, various classes of authentication: AuthenticationStandard, AuthenticationActiveDirectory, XafariAuthentication, and different classes of users and roles: SecuritySystemRole, SecuritySystemUser, Xafari.Northwind.Security.InheritedRole, Xafari.Northwind.Security.InheritedUser, various types of logon parameters: XafariAuthenticationLogonParameters.

In the property securityAssemblies, assemblies which are used in the authentication subsystem types of security (authentication classes, classes of users, roles, classes logon parameters) must be listed separated by semicolons. If these assemblies are XAF modules, then they must also be specified in the key Modules of the section.
Using optional properties roleTypeName, userTypeName custom implementation of roles and users classes (name of the class with the namespace) are added if necessary. These values are used by the console utility to initialize properties SecurityStrategyComplex.RoleType and SecurityStrategyComplex.UserType respectively.

The section describes the class of authentication. Pproperty typeName is assigned to the class name with the namespace. The utility creates an instance of the class and uses it to set the property SecurityStrategyComplex.Authentication.

To create an instance of authentication class, initialization of some of its properties may be required. For this purpose, a subsection has been added to the section. Names and values of properties which are being initialized are specified by adding the elements.

To generate the values specified in the property value in the utility code, method System.ComponentModel.TypeConverter.ConvertFromString is used for the type of the property which is being initialized. If the property is being initialized with the type System.Type, an instance of the class mentioned in value is created to generate its value.
In the section, the connection string to the database is specified in the same way as in the main application.

In section the parameter DbApplicationName must be set to the name of the main application, working with the database. This name is used when checking the compatibility with the database.
Modules which directly implement various commands must be listed in the key Modules in the section.

When you run the utility for the first time, an exception to incompatibility with the database may occur. In this case, you must perform a built-in utility command which updates the database (using the command line switch / dbupdate, described in the next section). The standard utility DBUpdater towards RunCmd.exe does not work correctly on the new database. If the database has already been used, then DBUpdater can be used in order to bring the database to a consistent state.

The keys of the command-line utility to execute commands

Any of the keys:

is used to display a quick reference to the use of the utility.
The list of commands available for execution can be obtained by running the utility from any keys:

The description of the parameters of this command is displayed using the keys:

To run an arbitrary command, its name and parameters in the form of colon-separated pairs: name:value:

If this command is given as the first command-line argument, the key /command or /c is not required.
At the command line of the utility, multiple commands can be specified. In this case, they will be executed in the order in which they are listed.
It is possible to specify a list of commands in a text file whose name is passed in the utility as the parameter of the key:

Each command with its own parameters has a single line in the text file. Commands must have the following form:

To specify authentication settings, the key is used:

The utility interprets pairs parameter:value, which are passed to the command line and separated by a colon as the names and values of properties of a class that describes the logon parameters (eg, class properties of XafariAuthenticationLogonParameters). The utility creates an instance of the logon parameters, sets its properties to the specified values on the command line and uses the resulting instance of authentication.

Various command line arguments can also be listed in any text file. Commands can be located both on the same line and on several lines of the file. To use the reading arguments from a file, the following key is used:

There can be a few of such keys on the utility command line
In the case of a mismatch with the database, the following key must be used:

The standard procedure of checking the compatibility of the database and the update will be carried out. The optional parameter silent allows a silent update without user participation.