Extending Robin Using the SDK

Robin can be extended through its SDK. This means you can create your own modules and actions. That way, specialized functionality can be utilized through custom automation scripts.

In order to extend Robin using its SDK the following are required:

  • An IDE (Integrated Development Environment - e.g. Visual Studio) you can write C# on.
  • Robin installed on the machine Get Robin Now

In this guide, Visual Studio 2019 was utilized.

In the first part we are going to be utilizing Robin’s VS templates to create a custom module.
In the second part we are going to create a module from scratch, doing everything manually.
The first part alone will be sufficient to help you jumpstart creating your own modules but we strongly suggest checking the second part if you want to see how everything runs under the hood.

Part 1: Using Visual Studio templates

Creating your own, custom automation actions is really simple and straightforward.
Robin’s installer comes pre-packed with templates for Visual Studio (VS 2017 / 2019).

It only takes 3 steps after that.

  • Create a new project using Robin templates
  • Build the project
  • Transfer the generated .dll in the Custom modules folder Robin installation folder

Your custom module is now ready to be utilized through Robin’s editor.

Let’s take a closer look..

When extending the SDK keep in mind the following analogy:
1) Every project (.dll) is a Module
and
2) Actions of this Module are represented by classes inside that project.

After installing Robin (and templates for Visual Studio), open Visual Studio and choose one of the following options:

  • Sample Robin Module Project creates a pre-configured project, including two sample actions.
  • Empty Robin Module Project creates a pre-configured project without any actions.

    For our examples we are going to use the Sample Robin Module Project.

A project including a simple action (Action1.cs) inside a category and a conditional action (Action2.cs) has been created. Let’s modify those actions to create our custom module.

This is how the Action1.cs looks out of the box:

The majority of actions have parameters (Input or Output).
Input and Output parameters are represented by classic C# properties.
Each property should have an appropriate C# attribute, either [InputArgument] or [OutputArgument] to dictate its type and how they are presented in the Robin editor.

You can pre-populate your parameters by setting a default value C# attribute. For example, the default value of the InputArgument, is “Developer”

By applying this, and modifying the Execute method to return an Output, the custom action should look as follows.

using System;
using System.ComponentModel;
using Robin.Core;
using Robin.Core.Attributes;

namespace CustomSampleModule
{
    [Action(Order = 1, Category = "TestCategory")]
    [Throws("ActionError")] // TODO: change error name (or delete if not needed)
    public class Action1 : ActionBase
    {
        #region Properties

        // NOTE: You can find sample description and friendly name entries in Resources

        [InputArgument, DefaultValue("Developer")]
        public string InputArgument1 { get; set; }

        [OutputArgument]
        public string OutputArgument1 { get; set; }

        #endregion

        #region Methods Overrides

        public override void Execute(ActionContext context)
        {
            try
            {
                OutputArgument1 = $"Hello, {InputArgument1}";
            }
            catch (Exception e)
            {
                if (e is ActionException) throw;

                throw new ActionException("ActionError", e.Message, e.InnerException);
            }
        }

        #endregion
    }
}

Once the project is created you are good to go!

Accessing the Custom Module from the Editor

Double click on the project’s “Properties”.

In order for the custom modules to be available through the Robin editor, their assembly name should have the following format: “[company/dev name].Modules.[module name]”

Choose the build configuration for the solution (Debug/Release) and build it.

To finalize the creation of the Custom Module, the generated .dll file ([Your Project’s name].dll) is required. The file can be found under the bin/release or bin/debug folder of the project.

Copy the .dll file only, inside the Custom Modules folder, located in the root directory of your Robin installation.
Now the custom module can be accessed right from your editor and its functionality can be implemented in your scripts.

Adding descriptions to Custom Actions

It is best practice to provide a description for the modules and actions so that RPA developers will know how to best utilize them.

Descriptions are displayed in the hint tooltip, in the Robin editor when selecting modules and actions from the autocomplete menu.
To add a description you have to modify the “Resources.resx” file under the Project “Properties”.

The format of the descriptions for Modules and Actions should be as follows:

  • “Module_Description” or “Action_Description” respectively in the name field.
  • The description in the value field.

It is a best practice to denote what it is you are describing in the comment field (e.g. Module, Action etc.)

It is also recommended to provide descriptions for parameters. Their format should be as follows: “Action_Parameter_Description”.

Custom Modules Categories

Modules can include categories and subcategories for better Action organization.

In order to separate Custom Actions in categories, subcategories etc. you must modify the [Action] attribute which precedes the class that represents the custom Action in the following manner:

[Action(Category = "category.subcategory")]

A Module can have multiple categories. Similarly, categories can be comprised by subcategories. This structure can be indefinite.

Action1 belongs in a category out of the box:

The “Order” attribute dictates the order by which actions are previewed in the editor:

Adding a new Action

Adding a new action in your Robin projects is really simple.
You right click your project and add a new item:

By scrolling or inputting “Robin” at the search text box, you are presented with two available options:

You can either create a simple Robin Action or a Conditional Action.

Conditional Actions

Conditional actions are actions that return either “True” or “False”.
File.Exists Robin action is a good example of a conditional action.

using System;
using Robin.Core;
using Robin.Core.Attributes;

namespace CustomSampleModule
{
    [ConditionAction(ResultPropertyName = nameof(Result))]
    [Throws("ActionError")] // TODO: change error name (or delete if not needed)
    public class ConditionAction2 : ActionBase
    {
        #region Properties

        public bool Result { get; private set; }

        [InputArgument]
        public string InputArgument1 { get; set; }

        [OutputArgument]
        public string OutputArgument1 { get; set; }

        #endregion

        #region Methods Overrides

        public override void Execute(ActionContext context)
        {
            try
            {
                //TODO: add action execution code here
            }
            catch (Exception e)
            {
                throw new ActionException("ActionError", e.Message, e.InnerException); // TODO: change error name (or delete if not needed)
            }

            // TODO: set values to Output Arguments and Result here
            // Result = ...
            // OutputArgument1 = ...
        }

        #endregion
    }
}

Notice the “Result” boolean variable.
Returning to our File.Exists example, this action doesn’t return an Output Argument.
You can pass it as an input to an IF statement though.
What is checked there is the value held by the Result variable.

There is another (advanced) topic about Actions, Custom Action Selectors. To explore it, go to Part 3 of the SDK guide.

Part 2: Manual Approach

What happens behind the scenes when using the templates really boils down to next five steps:

  • Create a Class Library Project (.dll) using .NET Framework 4.6
  • Add Robin.Core to your projects references
  • Add a new class that inherits from ActionBase class
  • Build your project in Release mode
  • Transfer the generated .dll in the Robin installation folder

….and voila!

Your custom module and actions are ready to be utilized!

Pre-configuration for custom actions development

Begin by creating a new Class Library (.NET Framework) project.

Give your project a distinct name (remember, it describes the Custom Module)

Also, set to use .NET Framework version to 4.6.

To have access to the SDK you need to include Robin.Core.dll library file (found in your Robin installation folder, usually “C:\Program Files\Robin”) in the project’s References.

Right Click on the Project’s “References” and select the “Add Reference…” option.

In the Reference Manager browse for the Robin.Core.dll and after selecting it click on the “OK” button.

The Robin.Core.dll is now included in your Project’s References.

Creating a simple Action

To form an action in the Custom Module just created, follow the steps described below.

First, delete the auto-generated Class1.cs file.

Now, create a new class inside your project to represent your custom Action and give it a distinct name also, Include the Robin.Core and Robin.Core.Attributes namespaces.

All classes representing actions should have an [Action] attribute above your class.

The class should have public access and inherit from ActionBase class.

The majority of actions have parameters (Input or Output).
Input and Output parameters are represented by classic C# properties.
Each property should have an appropriate C# attribute, either [InputArgument] or [OutputArgument] to dictate its type and how they are presented in the Robin editor.

You can pre-populate your parameters by setting a default value C# attribute.

For example, the default value of the InputArgument, is “Developer”

using Robin.Core;
using Robin.Core.Attributes;
using System.ComponentModel;

namespace CustomModule 
{
    [Action]
    public class CustomAction : ActionBase
    {
        [InputArgument, DefaultValue("Developer")]
        public string InputName { get; set; }
        [OutputArgument]
        public string DisplayedMessage { get; set; }
        public override void Execute(ActionContext context)
        {
            DisplayedMessage = $"Hello, {InputName}";
        }
    }
}

Applying this, the new custom action would look as follows.

You now have a complete, new custom module that can be utilized through Robin scripts.

Adding descriptions to Custom Actions

It is a best practice to provide a description for the modules and actions so that RPA developers will know how to best utilize them.

Descriptions are displayed in the hint tooltip, in the Robin editor when selecting modules and actions from the autocomplete menu.
To add a description you have to modify the “Resources.resx” file under the Project “Properties”.

The suggested approach is to create a “Resource.resx” file inside the Properties folder of the module project.
The new “.resx” file should be named “Resources.resx”.



The format of the descriptions for Modules and Actions should be as follows:

  • “Module_Description” or “Action_Description” respectively in the name field.
  • The description in the value field.

It is a best practice to denote what it is you are describing in the comment field (e.g. Module, Action etc.)

It is also recommended to provide descriptions for parameters. Their format should be as follows: “Action_Parameter_Description”.

Accessing the Custom Module from the Editor

Double click on the project’s “Properties”.

In order for the custom modules to be available through the Robin editor, their assembly name should have the following format: “Robin.Modules.ModuleName”.

Change the solution configuration to “Release” and build the solution.

To finalize the creation of the Custom Module, the generated .dll file ([Your Project’s name].dll) is required. The file can be found under the bin/release folder of the project.

Copy the .dll file only inside the path of the Robin installation.

Now the custom module can be accessed right from your editor and implement its functionality in your scripts.

By modifying slightly the script we get the following outcome:

You can see that your Modules and Actions are up and running.

Custom Modules Categories

Modules can include categories and subcategories for better Action organization.

In order to separate Custom Actions in categories, subcategories etc. you must modify the [Action] attribute which precedes the class that represents the custom Action in the following manner:

[Action(Category = "category.subcategory")]

A Module can have multiple categories. Similarly, categories can be comprised by subcategories. This structure can be indefinite.

Below the Custom Module, contains the CustomCategory which in turn contains the CustomSubcategory. The “CategorizedCustomAction” resides inside the CustomSubcategory.

using Robin.Core;
using Robin.Core.Attributes;
using System;

namespace CustomModule
{
    [Action(Category = "CustomCategory.CustomSubcategory")]
    public class CategorizedCustomAction : ActionBase
    {
        [OutputArgument]
        public string DisplayedMessage 
        { get; set; }
        public override void Execute(ActionContext context)
        {
            DisplayedMessage = $"Action is inside: {GetAttribute(typeof(CategorizedCustomAction))}";
        }


        // Method to retrieve the Attribute Category values from a class
        public static string GetAttribute(Type t)
        {
            // Get instance of the attribute.
            ActionAttribute  MyAttribute = (ActionAttribute)Attribute.GetCustomAttribute(t, typeof(ActionAttribute));

            return MyAttribute.Category.ToString();
        }
    }
}

As explained previously, to create a description for the actions and their parameters you must follow the following format when adding them in the Resources.rsx file,
for Actions:

“CategoryName_SubCategoryName_ActionName_Description”

for parameters:

“CategoryName_SubCategoryName_ActionName_ParameterName_Description”

The categories and subcategories, exactly like the modules are available through the Robin editor showing the set hint tooltip.

Part 3: Custom Action Selectors (Advanced Topic)

There are particular cases, in which a custom action might require to have more than one flavors.

An example, would be the “Launch Excel” action.

Using the “Excel.Launch” selector, the script will launch a blank excel document, whereas using the “Excel.LaunchAndOpen” selection will require the file path of the file to open.

The two actions mentioned above, are two selectors of a “Launch Excel” base action.

When creating your custom Actions you don’t have to re-write functionality. You can create a single “base” Action, setting its input and output parameters and then choose what would be visible in each flavor by utilizing Action Selectors.

Through Action Selectors a level of abstraction can be added over a single Action, allowing to retrieve specific functionality from the single “base” Action without having to re-write code to form a new variation of the Action every time.

Think of selectors as choices, filtering a single action and presenting only the information required according to the respective selection.

graph LR; B(Single Action) -->|All input/output parameters|C( ) C -->| Action Selector 1 | D(Action 1) C -->| Action Selector 2 | E(Action 2) C -->| ... | F(...) C -->| Action Selector X | G(Action X) linkStyle 3 opacity:0;

To form a new Action Selector, first create a central Action to be utilized by the Selectors. The central Action requires either a Boolean or an Enum property as an input C# argument. The value of this property determines which selector is utilized.

  • The most common way, is using an Enum.
    Especially when more than 2 selectors are needed, Enums is the only option.
  • For 2 selector cases, Booleans can be used.

Let’s see a sample “central” Action.

The central action is declared as a classic Action. Notice the first property (input argument) is an Enum. Based on that property’s value, the appropriate selector will become active.

To have the arguments ordered the way you prefer you set the Order value next to the InputArgument attribute.

using Robin.Core;
using Robin.Core.Attributes;
using System;
using System.ComponentModel;


namespace CustomModule
{
    [Action]
    public class CentralCustomAction : ActionBase
    {
        [InputArgument, DefaultValue(SelectorChoice.Selector1)]
        public SelectorChoice Selector { get; set; }

        [InputArgument(Order = 1)]
        public string FirstName { get; set; }

        [InputArgument(Order = 2)]
        public string LastName { get; set; }

        [InputArgument(Order = 3)]
        public int Age { get; set; }

        [OutputArgument]
        public string DisplayedMessage { get; set; }
        public override void Execute(ActionContext context)
        {
            if (Selector == SelectorChoice.Selector1 )
            {
                DisplayedMessage = $"Hello, {FirstName}!";
            }
            else if (Selector == SelectorChoice.Selector2)
            {
                DisplayedMessage = $"Hello, {FirstName} {LastName}!";
            }
            else // The 3rd Selector was chosen 
            {
                DisplayedMessage = $"Hello, {FirstName} {LastName}!\nYour age is: {Age}";
            }
        }
    }
}

Custom Action Selectors using Enums

For this example we are going to create 3 selectors.

A simple Enum will dictate the appropriate selector each time:

Selectors are represented by classes. Those classes must inherit the ActionSelector<> class.

In the UseName() method, the name of the action that will appear in the editor is declared.

using Robin.Core.ActionSelectors;

namespace CustomModule
{
    public class Selector1 : ActionSelector<CentralCustomAction>
    {
        public Selector1()
        {
            // The name of the Action as it will be presented inside the Robin editor
            UseName("DisplayOnlyFirstName");
            Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector1);

            ShowAll();
            Hide(p => p.LastName);
            Hide(p => p.Age);

            // or
            // Show(p => p.FirstName);
            // Show(p => p.DisplayedMessage);
        }
    }
}

Remember, the Selector classes should not be declared as Actions. The only action is the central one. Selectors act as filters.

In this specific example we want to display only one of the arguments, thus the others are filtered out.

Similar approach for Selector2:

using Robin.Core.ActionSelectors;

namespace CustomModule
{
    public class Selector2 : ActionSelector<CentralCustomAction>
    {
        public Selector2()
        {
            // The name of the Action as it will be presented inside the Robin editor
            UseName("DisplayFullName");
            Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector2);

            ShowAll();
            Hide(p => p.Age);
        }
    }
}

And Selector3 classes:

using Robin.Core.ActionSelectors;

namespace CustomModule
{
    public class Selector3 : ActionSelector<CentralCustomAction>
    {
        public Selector3()
        {
            // The name of the Action as it will be presented inside the Robin editor
            UseName("DisplayFullDetails");
            Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector3);

            ShowAll();
        }
    }
}

The final execution is achieved through the Execute(ActionContext context) method which resides in the central action.

Based on the selector, the respective values filtered are displayed.

Custom Action Selectors using Boolean

An example utilizing Boolean instead of enums is demonstrated below.

using Robin.Core;
using Robin.Core.ActionSelectors;
using Robin.Core.Attributes;
using System;
using System.ComponentModel;


namespace CustomModule
{
    [Action]
    public class CentralCustomActionWithBoolean : ActionBase
    {
        [InputArgument, DefaultValue(true)]
        public bool TimeExpired { get; set; }

        [InputArgument]
        public string ElapsedTime { get; set; }
        [InputArgument]
        public string RemainingTime { get; set; }
        [OutputArgument]
        public string DisplayedMessage { get; set; }
        public override void Execute(ActionContext context)
        {
            DisplayedMessage = TimeExpired ? $"The has expired. Elapsed time: {ElapsedTime}" : $"Remaining time: {RemainingTime}";
        }        
    }
    public class NoTime : ActionSelector<CentralCustomActionWithBoolean>
    {
        public NoTime()
        {
            UseName("TimeHasExpired");
            Prop(p => p.TimeExpired).ShouldBe(true);
            ShowAll();
            Hide(p => p.RemainingTime);
        }
    }

    public class ThereIsTime : ActionSelector<CentralCustomActionWithBoolean>
    {
        public ThereIsTime()
        {
            UseName("TimeHasNotExpired");
            Prop(p => p.TimeExpired).ShouldBe(false);
            ShowAll();
            Hide(p => p.RemainingTime);
        }
    }
}

Setting Descriptions for Custom Action Selectors.

To create a description for the selectors, use the following format in the .resx file:
SelectorName_Description.