{tocify} $title={Table of Contents}
Create custom actions
In
Bot Framework Composer, actions are the main contents of a trigger. Composer
provides different types of actions, such as Send a response, Ask a question,
and Create a condition. Besides these built-in actions, additional actions can
be added through packages or by creating components that includes custom
actions.
This
article explains how to create a custom action that multiplies two inputs
together.
Setup the component project
To
create a custom action (or any component), first setup a new project, and add
the necessary package dependencies for working with adaptive dialogs and the
Bot Framework SDK.
• Locate
the .sln file for the bot, and open it in an editor (like Visual Studio or
Visual Studio Code).
• Add
a new project named MultiplyDialog to your solution. In Visual Studio
right-click on the solution in the Solution Explorer and select Add > New
Project. Use the Class Library project template.
• Add
a reference to the Microsoft.Bot.Builder.Adaptive.Runtime package. Use the same
version as the bot depends on.
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive.Runtime" Version="4.13.1" />
Add a project reference from the bot project to the component project. Right-click on the <myBot> project and select Add > Project Reference. Choose the MultiplyDialog project and click OK.
Build
the entire solution to restore all packages and validate the dependency tree.
Create the custom action
Actions
in Composer are special implementations of the Dialog base class. This allows
each action in the trigger to be pushed onto the dialog stack, and executed in
turn.
In
the new project, rename the Class1.cs file to MultiplyDialog.cs, and update
it's contents to look like the below:
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder.Dialogs;
using Newtonsoft.Json;
public class MultiplyDialog : Dialog
{
[JsonConstructor]
public MultiplyDialog([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base()
{
// enable instances of this command as debug break point
RegisterSourceLocation(sourceFilePath, sourceLineNumber);
}
[JsonProperty("$kind")]
public const string Kind = "MultiplyDialog";
[JsonProperty("arg1")]
public NumberExpression Arg1 { get; set; }
[JsonProperty("arg2")]
public NumberExpression Arg2 { get; set; }
[JsonProperty("resultProperty")]
public StringExpression ResultProperty { get; set; }
public override Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
var arg1 = Arg1.GetValue(dc.State);
var arg2 = Arg2.GetValue(dc.State);
var result = Convert.ToInt32(arg1) * Convert.ToInt32(arg2);
if (this.ResultProperty != null)
{
dc.State.SetValue(this.ResultProperty.GetValue(dc.State), result);
}
return dc.EndDialogAsync(result: result, cancellationToken: cancellationToken);
}
}
Create the schema file
The
.schema file for the component is a partial schema that will be merged into the
main .schema file for the bot. Although it is possible to edit the main
sdk.schema file for the bot directly, doing so is not recommended. Merging
partial schema files will isolate changes, allow for easier recovery from
errors, and enable easier packaging of your component for reuse.
Create
a new file in the project named MultiplyDialog.schema and update the contents
to the below:
{
"$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema",
"$role": "implements(Microsoft.IDialog)",
"title": "Multiply",
"description": "This will return the result of arg1*arg2",
"type": "object",
"additionalProperties": false,
"properties": {
"arg1": {
"$ref": "schema:#/definitions/integerExpression",
"title": "Arg1",
"description": "Value from callers memory to use as arg 1"
},
"arg2": {
"$ref": "schema:#/definitions/integerExpression",
"title": "Arg2",
"description": "Value from callers memory to use as arg 2"
},
"resultProperty": {
"$ref": "schema:#/definitions/stringExpression",
"title": "Result",
"description": "Value from callers memory to store the result"
}
}
}
Create the BotComponent class
The
adaptive runtime will dynamically discover and inject components at startup
time.
Create
a new MultiplyDialogBotComponent.cs file in the project and update the contents
to
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class MultiplyDialogBotComponent : BotComponent
{
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
// Anything that could be done in Startup.ConfigureServices can be done here.
// In this case, the MultiplyDialog needs to be added as a new DeclarativeType.
services.AddSingleton<DeclarativeType>(sp => new DeclarativeType<MultiplyDialog>(MultiplyDialog.Kind));
}
}
In
the appsettings.json file of the bot project (located at \settings)to include
the MultiplyDialogBotComponent in the runtimeSettings/components array.
"runtimeSettings": {
"components": [
{
"name": "MultiplyDialog"
}
]
}
Build
the entire solution to validate everything was added correctly.
Merge schema files
The
final step is to merge the partial schema file from the MultiplyDialog project
into the main sdk.schema file for the bot. This makes the custom action
available for use in Composer.
• Navigate
to the schemas folder in the myBot project. This folder contains a PowerShell
script and a bash script. Use an elevated PowerShell terminal to execute the
PowerShell script. You will need to either copy/paste the contents of the
script, or ensure your execution-policy allows for running unsigned scripts.
• To
validate the script executed successfully, search for MultiplyDialog inside the
MyBot\schemas\sdk.schema file and validate that the partial schema from the
MultiplyDialog.schema file is included in sdk.schema.
Test
Open
the bot project in Composer to test the added custom action. If the project is
already loaded, return to Home in Composer, and reload the project.
• Open
the bot in Composer. Select a trigger add the custom action to.
• Select
+ under the trigger node to see the actions menu. Then choose Custom Actions
> Multiply.
• On
the Properties panel on the right side, enter two numbers in the argument
fields: Arg1 and Arg2. Enter "dialog.result" in the Result property
field.
• Add
a Send a response action. Enter "The result is: ${dialog.result}" in
the Language Generation editor.
• Select
Start Bot to test the bot in Web Chat. When triggered, the bot will respond
with the test result entered in the previous step.
How to pass Appsettings settings to Custom Action
You
can just use the settings scope memory. for example
"settings.yourSettings". Please refer to the custom action sample:
StringExpression yourSettings = "settings.yoursettings"
var yourSettingsValue = yourSettings.GetValue(dc.State);
If
you sent an multi element json element as collection you can send while passing
in parameter:
json(settings.yourSettings)
In Appsettings
"yourSettings": {
"value1": true
}
In custom Action
[JsonProperty("appSettings")]
public ValueExpression AppSettings { get; set; }
dynamic appSettings = AppSettings.GetValue(dc.State);
var yourAppsettings = appSettings["yourSettings"]
var value1 = appSettings["yourSettings"]["value1"]