Nintex Plugin Development
This topic is intended for computer programmers who need to know how to develop Nintex plugins, for use in the Run .NET Plugin Method advanced command in Nintex Studio.
For more information about the Run .NET Plugin Method command, see the Advanced Commands Reference Guide – Run .NET Plugin Method.
Plugin framework
A plugin framework is the most common design pattern used for application extension.
Plugin interfaces enable third-party developers to extend theNintex RPA Platform and can be used to create an entirely new application.
Most plugin frameworks provide the option of loading plugins at runtime and on demand. However, a plugin must sometimes be unloaded because:
- It consumes excessive resources
- It has not been used for a certain amount of time
Loading an assembly in .NET is generally easy and, for the most part, does not require high plugin design complexity. However, unloading a .NET assembly increases the design complexity: It requires that you implement an interface so that the plugin manager can interact with the loaded assembly.
For the application to be able to unload the plugin, it must first load the plugin assembly in a separate .NET application domain. Loading the assembly in a separate application domain enables the plugin to have its own configuration file and decouples the plugin from the rest of the application. To be able to load and instantiate an object of type ILeoPlugIn, the class that implements the ILeoPlugIn interface must also inherit from the .NET class MarshalByRefObject.
public interface ILeoPlugIn
{
string Name { get; }
void Initialize();
void Shutdown();
List<LeoPlugInParams> Execute(LeoPlugInMethod pMethod);
}
The reason it must inherit from MarshalByRefObject is that it is going to be accessed from the main application domain. For the current cross-domain constraint all the same design constraints that exist in an application that uses the Remoting API, also applies in this case. Therefore, to simplify the plugin development, it is suggested to define an abstract class that inherits from MarshalByRefObject and implements the ILeoPlugIn interface.
public abstract class LeoPlugIn : MarshalByRefObject, ILeoPlugIn
{
public abstract string Name { get; }
public abstract void Initialize();
public abstract void Shutdown();
List<LeoPlugInParams> Execute(LeoPlugInMethod pMethod);
}
Once you implement the abstract class LeoPlugIn, you must add an assembly attribute in the plugin assembly, the most obvious place being the AssemblyInfo.cs file.
[Serializable]
[AttributeUsageAttribute(AttributeTargets.Assembly,
Inherited = false, AllowMultiple = false)]
public sealed class LeoPlugInAttribute : Attribute
{
public string PlugInName { get; private set; }
public string EntryType { get; private set; }
public LeoPlugInAttribute (string pluginName, string entryType
{
PlugInName = pluginName;
EntryType = entryType;
}
}
Usage:
[assembly: LeoPlugInAttribute("PlugInA", "SamplePlugIns.PlugInA")]
This indicates to the LeoPlugInLoader that:
- The assembly is a plugin
- The plugin name is PlugInA
- The entry class (the class that inherits from the LeoPlugIn) is of the type name SamplePlugIns.PlugInA
The LeoPlugInLoader creates a temporary app domain and load plugin assembly from a provided path. It creates an instance of LoadAssemblyAttributesProxy and query for the assembly LeoPlugInAttribute attribute. Once the assembly is verified, the LeoPlugInAttribute is stored for the instantiation phase. This information is later used by the loader to create an instance of the entry class.
public class LoadAssemblyAttributesProxy : MarshalByRefObject
{
public PlugInAttribute[] LoadAssemblyAttributes(string assFile)
{
Assembly asm = Assembly.LoadFrom(assFile);
var plugInAttributes =
asm.GetCustomAttributes(typeof (PlugInAttribute), false) as PlugInAttribute[];
return plugInAttributes;
}
}
The LeoPlugInLoader class creates an AppDomainSetup object, sets the name to the plugin name and sets the configuration file to the plugin's *.config file (i.e. PlugInName.config.dll), and finally creates the plugin's own application domain (common level of isolation). Once the application domain is created, it remains for future use in expressions. The LeoPlugInLoader instantiates the entry class in its corresponding AppDomain by invoking the CreateInstanceAndUnwrap method. This method returns a proxy object to the entry class and is cast to the ILeoPlugIn.
Plugin methods
The execution of plugin methods is performed by PlugInManager which in turn resides in the external executable PlugInLauncher. In order to execute specific methods, you must implement the abstract class LeoPlugIn and decorate the particular method with the LeoPlugInMethodAttribute attribute. This attribute indicates that the current method should be published and used within the Nintex expression. The attribute also applies the Nintex policy regarding method signature, validates return type and input arguments permitted by Nintex expression .NET types:
-
Blittable
-
Some non-blittable types: string, object, Boolean
Plugin usage
Nintex plugins can be defined and used in advanced commands in two ways:
-
By location (defining a path)
By location
The plugin is located by its path on the client's machine. This is a solution for IT managers that distribute, install, update and uninstall software applications remotely. The LeoPlugInLoader will try to load the potential plugin into a dedicated application domain, inspect all published methods for existence of a specific expression's method, and validate its signature. In case of any error during the initialization or invocation phases, the expression ends silently, but a verbal message is written to a log. This solution simplifies updating of a particular plugin without involving Nintex Studio, unless there are changes in the method signature.
Embedding
The plugin is embedded into the particular script's assets. This solution (installation free) distributes the plugin and is used by the expression on demand. As the plugin developer, you will be responsible for the content and its dependencies. There is no reference validation on the Nintex platform’s behalf. The LeoPlugInLoader will try to load the plugin into a dedicated application domain, so there is no need for published methods inspection or its signature validation. If there are any errors during the initialization or invocation phases, the expression ends silently, but a verbal message is written to a log. The updating of a particular plugin can only be done through the Nintex Studio interface and by redefining its in/out parameters.
Developing a Nintex plugin
To create a Nintex plugin:
Add a reference to Leo.Plugin.Library.dll
Use the Add Reference dialog box to make LeoPlugIn a reference in your project.
Mark assembly as Nintex plugin
Add an assembly attribute in the plugin assembly, the most obvious place being the AssemblyInfo.cs file.
using Kryon.Leo.Infrastructure.Plugin.Library.Attributes;
[assembly: LeoPlugInAttribute("PlugInA", "SamplePlugIns.PlugInA")]
This line of code indicates that the assembly is a plugin. The plugin name is PlugInA and that the qualified entry type (the class that inherits from the LeoPlugIn) is SamplePlugIns.PlugInA (includes namespace).
Therefore, make sure there is a full match between your class name, namespace and LeoPlugInAttribute definition.
Derive from LeoPlugIn
To make this class a Nintex plugin, make sure that it derives from a LeoPlugIn parent class in the namespace Kryon.Leo.Infrastructure.Plugin.Library.
using Kryon.Leo.Infrastructure.Plugin.Library;
using Kryon.Leo.Infrastructure.Plugin.Library.Attributes;
namespace SamplePlugIns
{
public class PlugInA : LeoPlugIn
{
public PlugInA
{
}
}
}
Implement LeoPlugIn
Basically, there is an interface that must be implemented by the plugin implementer and a plugin manager will be able to interact with loaded assembly. The parent LeoPlugIn parent implements the interface and marks all signatures of methods, delegates or events as abstract in sake of concrete implementation.
When creating your own logic:
-
To initialize your own objects, use the initialize method, which is invoked before the execution process
-
To clean up/dispose your own objects, use the shutdown method, which is invoked prior to the Nintex plugin disposal
public abstract class LeoPlugIn : MarshalByRefObject, ILeoPlugIn
{
public abstract string Name { get; }
public abstract void Initialize();
public abstract void Shutdown();
List<LeoPlugInParams> Execute(LeoPlugInMethod pMethod);
}
-
Name: The runtime name of plugin as you defined it
-
Initialize (can be overridden): Method is called after plugin instantiation
-
Shutdown (can be overridden): Called before disposing the plugin
-
Execute: Encapsulates the invocation of a concrete method and is responsible for input arguments and return values
using Kryon.Leo.Infrastructure.Plugin.Library;
using Kryon.Leo.Infrastructure.Plugin.Library.Attributes;
namespace SamplePlugIns
{
public class PlugInA : LeoPlugIn
{
public override void Initialize()
{
Console.WriteLine(Name + " Initializing...");
}
}
}
Add plugin to the plugin library
Follow these steps to add a plugin to the plugin library:
-
From the Nintex Studio Editor window, go to Tools > Plugin Manager
The Plugin Manager window appears. -
Depending on whether your plugin is embedded or local, click the corresponding pane’s Add button.
-
Navigate to the folder in which your DLL plugin is saved and select it.
-
Your plugin is added and can be used from the Run .NET Plugin Method advanced command.
/Studio_292.png)
/Studio_293.png)
Apply plugin to individual methods
A .NET LeoPlugInMethod attribute declaration is all it takes to wire your logic into one or more existing class methods that should be invoked by the Nintex RPA Platform. Simply apply it to individual methods.
using Kryon.Leo.Infrastructure.Plugin.Library;
using Kryon.Leo.Infrastructure.Plugin.Library.Attributes;
namespace SamplePlugIns
{
public class PlugInA : LeoPlugIn
{
[LeoPlugInMethod]
public string Add(int a, int b)
{
return string.Format("{0} + {1} = {2}", a, b, a + b);
}
}
}
As a result of applying the plugin method attributes, the method appears as an advanced command action in the Advanced Commands toolbox:
To launch the method, Nintex Studio users must click the Run .NET Plugin Method command in Studio’s Advanced Commands editor: