Galaktikasoft

An Example of Using Command Line Utility RunCmd

There are some tasks (commands) that require maximum automation and minimum user interaction. In general, such conditions are satisfied by a console application that allows a user to specify the command, set parameters and start execution. Of course, all this should be implemented as an organic part of a XAF application, i.e. command is a function of the application, it is coded in the XAF module. Xafari framework proposes an architecture to implement commands and supplies RunCmd.exe console application to execute commands. The framework provides a number of implemented commands: to import (export) data, to create report etc.

This post describes how to apply this mechanism.

Create XAF WindowsFormApplication, name it RunCmdExample. Add BO business class to the RunCmdExample Module project. The following code demonstrates this.

[DefaultClassOptions]
public class BO : BaseObject
{
    public BO(Session session) : base(session) { }

    public string Name { get; set; }
    public string Description { get; set; }
}

Set Security System as you can see in the application screenshots:

Set LogonParametersType to the "DevExpress.ExpressApp.Security.ChangePasswordOnLogonParameters".

Add a new XAF Module to the solution, name it CommandModule. Since CommandModule is used exclusively for RunCmd.exe, is better to remove extra folders and files. In this example, the commands are implemented in a separate module, but it is not necessary and you can implement command in any application module.

Add RunCmdExample Module to the CommandModule. You can do it in the code or use designer. If you wish to add an extra module in the code, use the following code snippet:

private void InitializeComponent()
{
    this.RequiredModuleTypes.Add(typeof(RunCmdExample.Module.RunCmdExampleModule));
}

Add reference to the Xafari.dll assembly and set CopyLocal property to "True".

Now we can implement two commands. Add two command classes to CommandModule: it is SecurityInformation and DataInformation. SecurityInformation command will display a list of users or roles. SecurityInformation command will display determined columns of BO type from the database.

The following code snippet defines SecurityInformation and DataInformation classes:

public class SecurityInformation : CommandExtIOBase
{
    public override string Description
    {
        get { return "SInfo command shows information about Roles and Users from DataBase"; }
    }

    protected override void ExecuteCore(IDictionary parameters)
    {
        var parameterValue = parameters["Param"].ToString();
        if (parameterValue.Equals("Users", StringComparison.OrdinalIgnoreCase))
            DisplayUsers();
        else if (parameterValue.Equals("Roles", StringComparison.OrdinalIgnoreCase))
            DisplayRoles();
        else
            Out.WriteLine("Invalid parameter value!");
    }

    private void DisplayRoles()
    {
        Out.WriteLine("\nRoles:");
        var roles = Application.CreateObjectSpace().GetObjects();

        foreach (var role in roles)
            Out.WriteLine("  {0}", role.Name);
    }

    private void DisplayUsers()
    {
        Out.WriteLine("\nUsers:");
        var users = Application.CreateObjectSpace().GetObjects();

        foreach (var user in users)
            Out.WriteLine("  {0}", user.UserName);
    }       

    public override string Name
    {
        get { return "SInfo"; }
    }

    public override IEnumerable ParametersDescription
    {
        get
        {
            yield return new CommandParameterDescription("Param", ", ", "Show information about Roles and Users from DB.");
        }
    }

    public override void ValidateParameters(IDictionary parameters)
    {
        base.ValidateParameters(parameters);

        var tableName = parameters["param"].ToString();
        if (!tableName.Equals("Users", StringComparison.OrdinalIgnoreCase) &&
            !tableName.Equals("Roles", StringComparison.OrdinalIgnoreCase))
        {
            throw new ArgumentException(string.Format("Недопустимое значение параметра Param:\"{0}\"", tableName));
        }
    }

    private IObjectSpace objectSpace { get; set; }
}


public class DataInformation : CommandExtIOBase
{
    public override string Description
    {
        get { return "DInfo command shows information about BO object from DataBase"; }
    }

    protected override void ExecuteCore(IDictionary parameters)
    {
        var parameterValue = parameters["Column"].ToString();
        if (parameterValue.Equals("Name", StringComparison.OrdinalIgnoreCase))
            DisplayNameColumn();
        else if (parameterValue.Equals("Description", StringComparison.OrdinalIgnoreCase))
            DisplayDescriptionColumn();
        else if (parameterValue.Equals("All", StringComparison.OrdinalIgnoreCase))
            DisplayAllColumns();
        else
            Out.WriteLine("Invalid parameter value!");
    }

    private void DisplayAllColumns()
    {
        if (objectSpace == null)
            objectSpace = Application.CreateObjectSpace();
        var businesObject = objectSpace.GetObjects();
        Out.WriteLine("\n{0,-20} {1}", "Name:", "Description:");
        foreach (var obj in businesObject)
            Out.WriteLine(" {0,-20} {1}", obj.Name, obj.Description);
    }

    private void DisplayDescriptionColumn()
    {
        if (objectSpace == null)
            objectSpace = Application.CreateObjectSpace();
        var businesObject = objectSpace.GetObjects();
        Out.WriteLine("\nDescription:");
        foreach (var obj in businesObject)
            Out.WriteLine(obj.Description);
    }

    private void DisplayNameColumn()
    {
        if (objectSpace == null)
            objectSpace = Application.CreateObjectSpace();
        var businesObject = objectSpace.GetObjects();
        Out.WriteLine("\nName:");
        foreach (var obj in businesObject)
            Out.WriteLine(obj.Name);
    }

    public override string Name
    {
        get { return "DInfo"; }
    }

    public override IEnumerable ParametersDescription
    {
        get 
        {
            yield return new CommandParameterDescription("Column", ", , ", "Show content of BO object current column from DB.");
        }
    }

    public override void ValidateParameters(IDictionary parameters)
    {
        base.ValidateParameters(parameters);

        var tableName = parameters["Column"].ToString();
        if (!tableName.Equals("Name", StringComparison.OrdinalIgnoreCase) &&
            !tableName.Equals("Description", StringComparison.OrdinalIgnoreCase) &&
            !tableName.Equals("All", StringComparison.OrdinalIgnoreCase))
        {
            throw new ArgumentException(string.Format("Недопустимое значение параметра Column:\"{0}\"", tableName));
        }
    }

    private IObjectSpace objectSpace { get; set; } 
}

The CommandModule must support ICommandEnumerator interface to specify commands for the Run Cmd utility. Otherwise, Run Cmd will not "know" about the implemented commands. Add the following code to the CommandModule:

public IEnumerable Commands
{
    get 
    { 
        yield return new SecurityInformation(); 
        yield return new DataInformation(); 
    }
}

For ease of use in the future, add RunCmd.exe and RunCmd.exe.config files to the CommandModule project directory. Xafari installer places these files in the "…\Xafari Framework \Tools\RunCmd\" directory.
RunCmd.exe.config settings must match the settings of the global application.

Run Cmd Example solution contains a ready-to-use config file, you can download it and examine together with the solution.

The presence of the <system.diagnostics> block allows logging the execution process.

When working with Run Cmd, it is very convenient to use .bat-file. Add Run.bat file to the project and place following text in it:

@echo.

RunCmd.exe /dbupdate silent /h /cmdlist

@echo.

RunCmd.exe @sinfo.txt

@echo.

RunCmd.exe /batch dinfo.txt

The example above demonstrates different ways to set commands: to type in the command line and to load from file.

dinfo.txt file contains:

DInfo Column:All

DInfo Column:Name

DInfo Column:Description

These commands retrieve information from the database at the specified column. The image illustrates the result of these commands.

cinfo.txt file contains:

/paramlist SInfo /c SInfo Param:Users /c SInfo Param:Roles

The image illustrates the result of SInfo commands.

Before running the utility, you must build CommandsModule, build and run the application to populate the database.

Load solution: Run Cmd Example.