Scripted Activity
Casewhere Scripted Activity enables the execution of custom C# scripts within the workflow context. It offers a comprehensive range of APIs to support application development, including functionalities for working with data objects, evaluating rules, invoking plugins, and more. For detailed information about these APIs, consult the help links available in the editor.
In this article, we will explore some commonly used techniques in Scripted Actitivity.
Workflow variables
Persisted variables
Workflow persisted variables are stored in the database as part of the workflow data.
Setting a workflow variable: Workflow variables can accept any data type.
ctx.Set("Confirmed", true);
ctx.Set("Error", "Invalid data");
ctx.Set("Count", 999);
ctx.Set("SomeDataObject", aDataObject);
Getting a workflow variable: A workflow variable can be accessed throughout the workflow where it is created, including in scripted activities, navigation rules, validation rules, and more.
var isConfirmed = ctx.Get<bool>("Confirmed");
var error = ctx.Get<string>("Error");
var count = ctx.Get<int>("Count");
var aDataObject = ctx.Set("SomeDataObject"); // Read an object
Determine if a variable is created or not: The check disregards the variable's value. For instance, ctx.Has
will return true
even if the variable's value is null
or empty.
if (ctx.Has("Error")) Log.Error("An error occurred.");
Determine if a variable has a value or not: The check considers the variable's value and returns true
only when the value is neither null nor empty.
// A log event is created only if the error is not null or empty.
if (ctx.HasValue("Error")) Log.Error("An error occurred.");
Temporary variables
Storing large objects in workflow variables is not ideal, especially if there is no need to persist them, such as for display on the UI. To optimize performance, Casewhere introduces temporary variables for storing and accessing data in memory only. Temporary data will be discarded when Casewhere persists the workflow to the database.
Setting a temporary variable
ctx.SetTemp("Confirmed", true);
ctx.SetTemp("Error", "Invalid data");
ctx.SetTemp("Count", 999);
ctx.SetTemp("SomeDataObject", aDataObject);
Getting a temporary variable
var isConfirmed = ctx.GetTemp<bool>("Confirmed");
var error = ctx.GetTemp<string>("Error");
var count = ctx.GetTemp<int>("Count");
var aDataObject = ctx.GetTemp<DynamicDataObject>("SomeDataObject"); // Read an object
Determine if a temporary variable is created or not: The check disregards the variable's value. For instance, ctx.HasTempKey
will return true
even if the variable's value is null
or empty.
if (ctx.HasTempKey("Error")) Log.Error("An error occurred.");
Data object references
You can create a variable to store a reference to a data object and later use that reference to access the object. Casewhere stores only the data object ID and always fetches the latest data when accessing the referenced object.
// Activity 1: Set reference to newly created data objects
var applicationId = dataApi.Add("Application", new { ... });
ctx.Ref("Application", applicationId);
// Activity 2: Read the referenced data object
var application = ctx.Ref("Application");
Log.Info("Created application {@application}", application);
Access form data: Please note that Casewhere automatically creates references for data objects generated in form activities. You can access them using the form data source names.
It's also possible in Scripted Activity to set the data reference for Form Activity. This can be useful if you have a form with complex logic of data loading.
// Some complex validation before setting form data sources
if (!link.Get<bool>("IsActive"))
{
ctx.Set("Error", "cwss_error_not_found");
return null;
}
if (link.Get<bool>("RequiresLogin") && ctx.User.Has("IsAnonymousUser"))
{
ctx.Set("Error", "cwss_error_requires_login");
return null;
}
if (link.Get<DateTime>("ExpiresAt") <= DateTime.UtcNow)
{
Log.Warning("The link {linkID} is expired", linkID);
ctx.Set("Error", "cwss_error_expired");
return null;
}
//...
// Setting form data sources to be displayed on the UI in the next activity.
ctx.SetDataSource("CwSsLinkSecret", linkSecret["Id"]);
ctx.SetDataSource("CwSsLink", link["Id"]);
Working with events
You can emit custom events from a Scripted Activity using ctx.Emit
.
ctx.Emit("DeactivateLinkEvent", new
{
LinkId = "a_link_id"
});
In a event-handle workflow, you then can read data from the event:
var linkId = ctx.Input["Data"]["LinkId"];
dataApi.Update(linkId, new
{
IsActive = false
});
Please note that the event is sent to the event queue only if the Scripted Activity completes without errors. If the activity crashes, Casewhere will reject all events created during its execution. To ensure that events are sent to the queue regardless of the activity's status, you can use ctx.ForceEmit
, available since version 2.8.
Working with data objects
Create data
// Activity 1: Create new product with data from a plugin
var pluginApi = ctx.Use<IPluginApi>();
var dataApi = ctx.Use<IDataApi>();
var product = pluginApi.Invoke("TestDataPlugin", "GetProduct", new Dictionary<string, object>()).GetObject("Product");
var productData = new DynamicDataObject();
productData["Name"] = product["Name"];
productData["Picture"] = product["Picture"];
productData["Material"] = product["Material"];
productData["Description"] = product["Description"];
productData["Amount"] = product["Price"];
var productId = dataApi.Add("Product", productData);
ctx.Set("productId", productId); // Store the product ID to a workflow variable
Update data
// Activity 2: Update product with data from a plugin
var pluginApi = ctx.Use<IPluginApi>();
var dataApi = ctx.Use<IDataApi>();
var product = pluginApi.Invoke("TestDataPlugin", "GetProduct", new Dictionary<string, object>()).GetObject("Product");
var productData = new DynamicDataObject();
productData["Name"] = product["Name"];
productData["Picture"] = product["Picture"];
productData["Material"] = product["Material"];
productData["Description"] = product["Description"];
productData["Amount"] = product["Price"];
var productId = ctx.Get<string>("productId"); // Store the product ID to a workflow variable
dataApi.Update(productId, productData);
Delete data
// Delete the data object from the workflow input
var dataApi = ctx.Use<IDataApi>();
dataApi.Delete(ctx.Input.Id);
Read data
var product = ctx.Input;
var name = product.Get<string>("Name");
var price = product.Get<double>("Price");
var isActive = product.Get<bool>("IsActive");
var categories = product.GetList<string>("Categories");