diff --git a/docs/assets/MultiplyDialog.cs b/docs/assets/MultiplyDialog.cs new file mode 100644 index 0000000000..3b3b46177c --- /dev/null +++ b/docs/assets/MultiplyDialog.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using AdaptiveExpressions.Properties; +using Microsoft.Bot.Builder.Dialogs; +using Newtonsoft.Json; + +namespace CustomAction.MultiplyDialog +{ + /// + /// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result. + /// + public class MultiplyDialog : Dialog + { + [JsonConstructor] + public MultiplyDialog([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) + : base() + { + // enable instances of this command as debug break point + this.RegisterSourceLocation(sourceFilePath, sourceLineNumber); + } + + /// + /// Gets the unique name of this Adaptive Dialog. + /// + [JsonProperty("$kind")] + public const string Kind = "MultiplyDialog"; + + /// + /// Gets or sets memory path to bind to arg1 (ex: action.arg1). + /// + /// + /// Memory path to bind to arg1 (ex: action.arg1). + /// + [JsonProperty("arg1")] + public NumberExpression Arg1 { get; set; } + + /// + /// Gets or sets memory path to bind to arg2 (ex: action.arg2). + /// + /// + /// Memory path to bind to arg2 (ex: action.arg2). + /// + [JsonProperty("arg2")] + public NumberExpression Arg2 { get; set; } + + /// + /// Gets or sets caller's memory path to store the result of this step in (ex: dialog.result). + /// + /// + /// Caller's memory path to store the result of this step in (ex: dialog.result). + /// + /// + /// This is where the result of the Dialog is stored and accessible in Composer. + /// + [JsonProperty("resultProperty")] + public StringExpression ResultProperty { get; set; } + + /// + /// Override BeginDialogAsync to provide the custom action functionality. The inputs, in this case, + /// are define in Arg1 and Arg2. The result of the the dialog is stored in ResultProperty. + /// + public override Task 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); + } + } +} diff --git a/docs/assets/MultiplyDialog.csproj b/docs/assets/MultiplyDialog.csproj new file mode 100644 index 0000000000..d59836c631 --- /dev/null +++ b/docs/assets/MultiplyDialog.csproj @@ -0,0 +1,27 @@ + + + + Library + netcoreapp3.1 + CustomAction.MultiplyDialog + This library implements .NET support for the MultiplyDialog custom action sample BotComponent. + This library implements .NET support for the MultiplyDialog custom action sample BotComponent. + content + + msbot-component;msbot-action + + + + + + + + + + + + + + + + diff --git a/docs/assets/MultiplyDialog.schema b/docs/assets/MultiplyDialog.schema new file mode 100644 index 0000000000..f2928a25aa --- /dev/null +++ b/docs/assets/MultiplyDialog.schema @@ -0,0 +1,25 @@ +{ + "$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" + } + } +} \ No newline at end of file diff --git a/docs/assets/MultiplyDialogBotComponent.cs b/docs/assets/MultiplyDialogBotComponent.cs new file mode 100644 index 0000000000..2d5903e7dd --- /dev/null +++ b/docs/assets/MultiplyDialogBotComponent.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Dialogs.Declarative; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace CustomAction.MultiplyDialog +{ + /// + /// Definition of a that allows registration of + /// services, custom actions, memory scopes and adapters. + /// + /// To make your components available to the system you derive from BotComponent and register services to add functionality. + /// These components then are consumed in appropriate places by the systems that need them. When using Composer, Startup gets called + /// automatically on the components by the bot runtime, as long as the components are registered in the configuration. + public class MultiplyDialogBotComponent : BotComponent + { + /// + /// Entry point for bot components to register types in resource explorer, consume configuration and register services in the + /// services collection. + /// + /// Services collection to register dependency injection. + /// Configuration for the bot component. + 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(sp => new DeclarativeType(MultiplyDialog.Kind)); + } + } +} diff --git a/docs/extending-with-code.md b/docs/extending-with-code.md index 504a45bee7..30672bad5b 100644 --- a/docs/extending-with-code.md +++ b/docs/extending-with-code.md @@ -1,24 +1,160 @@ # Extending your bot with code -> Note: You should be familiar with the existing documentation on [custom actions](https://docs.microsoft.com/en-us/composer/how-to-add-custom-action) and [declarative dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-dialogs-declarative?view=azure-bot-service-4.0). This page is supplemental to those existing resources. +# Add custom actions in C# -Extending your bot with code is very similar to the currently published documentation (linked above). It differs from that documentation in the following ways: +## In this article -1. There is no need to eject your runtime & app code, as we do this for you at creation time. -1. The bot project we create for you on disk does not include the sample code as indicated in the documentation, you'll need to create the files from. - 1. You also don't add a reference to another project - just create the .cs and .schema files yourself, directly in your .sln that was created for you. -1. You'll probably need to manually run `dialog:merge` rather than use the PowerShell script. The command is below, execute from in the `/schemas` folder. +In Bot Framework Composer, [actions](concept-dialog#action) are the main +contents of a [trigger](concept-dialog#trigger). Actions help maintain +conversation flow and instruct bots on how to fulfill user requests. +Composer provides different types of actions, such as **Send a +response**, **Ask a question**, and **Create a condition**. Besides +these built-in actions, you can create and customize your own actions in +Composer. -```bash -bf dialog:merge "*.schema" "!**/sdk-backup.schema" "*.uischema" "!**/sdk-backup.uischema" "!**/sdk.override.uischema" "../*.csproj" "../package.json" -o sdk.schema -``` +This article shows you how to include a custom action named +`MultiplyDialog`. -You can also take a look at the [Graph package](/packages/Graph) for another example. +#### Note + +Composer currently supports the C\# runtime and JavaScript (preview) +Adaptive Runtimes. + +## Prerequisites + +- A basic understanding of [actions](concept-dialog#action) in Composer. +- [A basic bot built using Composer](quickstart-create-bot). +- [Bot Framework CLI 4.10](https://botbuilder.myget.org/feed/botframework-cli/package/npm/@microsoft/botframework-cli) or later. + +## Setup the Bot Framework CLI tool +---------------------- + +The Bot Framework CLI tools include the *bf-dialog* tool which will +create a *schema file* that describes the built-in and custom +capabilities of your bot project. It does this by merging partial schema +files included with each component with the root schema provided by Bot +Framework. + +Open a command line and run the following command to install the Bot +Framework tools: + + npm i -g @microsoft/botframework-cli + +## About this custom action +---------------------- + +This C\# custom action consists of the following: + +- A Composer project targeted for Dotnet. This can be any Composer project. One that already exists, or a new one you create. If you want to experiment risk free, create a new Blank Bot in Composer. This document assumes you create a Blank Bot named "MyBlankBot". + +- The custom action code [MultiplyDialog.cs](assets/MultiplyDialog.cs) class, which defines the business logic of the custom action. In this example, two numbers passed as inputs are multiplied, and the result is the output. + +- The custom action schema [MultiplyDialog.schema](assets/MultiplyDialog.schema), which describes the operations available. + + [Bot Framework Schemas](https://github.com/microsoft/botframework-sdk/tree/master/schemas) + are specifications for JSON data. They define the shape of the data + and can be used to validate JSON. All of Bot Framework's [adaptive + dialogs](/en-us/azure/bot-service/bot-builder-adaptive-dialog-introduction) + are defined using this JSON schema. The schema files tell Composer + what capabilities the bot runtime supports. Composer uses the schema + to help it render the user interface when using the action in a + dialog. Read the section about [creating schema files in adaptive + dialogs](/en-us/azure/bot-service/bot-builder-dialogs-declarative) + for more information. + +- A BotComponent, [MultiplyDialogBotComponent.cs](assets/MultiplyDialogBotComponent.cs) code file for component registration. BotComponents are loaded by your bot (specifically by Adaptive Runtime), and made available to Composer. + + **Note** You can create a custom action without implementing BotComponent. However, the Component Model in Bot Framework allows for easier reuse and is only slightly more work. In a BotComponent, you add the needed services and objects via Dependency Injection, just as you would in Startup.cs. + +## Adding the custom action to your bot project +------------------------------ + +1. Navigate to your Composer bot project folder (eg. C:\MyBlankBot) and create a new folder for the custom action project. For example, C:\MyBlankBot\MultiplyDialog. + +1. Save [MultiplyDialog.cs](assets/MultiplyDialog.cs), [MultiplyDialog.schema](assets/MultiplyDialog.schema), [MultiplyDialog.csproj](assets/MultiplyDialog.csproj), and [MultiplyDialogBotComponent.cs](assets/MultiplyDialogBotComponent.cs) to this new folder. + +1. Open your Blank Bot solution (C:\MyBlankBot) in Visual Studio. + +1. Add Existing project to the solution. + +1. In the MyBlankBot project, add a project reference to the MultiplyDialog project. Alternatively, you can add `` to the appropriate `ItemGroup` in MyBlankBot.csproj. + +1. Run the command `dotnet build` on the project to + verify if it passes build after adding custom actions to it. You + should be able to see the "Build succeeded" message after this + command. + +1. Edit MyBlankBot\settings\appsettings.json to include the MultiplyDialogBotComponent in the `runtimeSettings/components` list. + + ```json + "runtimeSettings": { + "components": [ + { + "name": "CustomAction.MultiplyDialog" + } + ] + } + ``` + +## Update the schema file +---------------------- + +Now you have customized your bot, the next step is to update the +`sdk.schema` file to include the `MultiplyDialog.Schema` file. This makes your custom action available for use in Composer. + +**You only need to perform these steps when adding new code extensions, or when the Schema for a component changes.** + +1) Navigate to the `C:\MyBlankBot\MyBlankBot\schemas` folder. This +folder contains a PowerShell script and a bash script. Run either one of +the following commands: + + ./update-schema.ps1 + + **Note** + + The above steps should generate a new `sdk.schema` file inside the + `schemas` folder. + +1) Search for `MultiplyDialog` inside the `MyBlankBot\schemas\sdk.schema` file and + validate that the partial schema for [MultiplyDialog.schema](assets/MultiplyDialog.schema) is included in `sdk.schema`. + +### Tip + +Alternatively, you can select the `update-schema.sh` file inside the +`MyBlankBot\schemas` folder to run the bash script. You can't click and run the +`powershell` file directly. + +## Test +---- + +Open the bot project in Composer and you should be able to test your +added custom action. If the project is already loaded, return to `Home` in Composer, and reload the project. + +1. Open your bot in Composer. Select a trigger you want to associate this custom action with. + +2. Select **+** under the trigger node to see the actions menu. You + will see **Custom Actions** added to the menu. Select **Multiply** + from the menu. + +3. 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. For example, enter `99` for each field. + +4. Add a **Send a response** action. Enter `99*99=${dialog.result}` in the Language Generation editor. + +5. Select **Restart Bot** to test the bot in the Emulator. Your bot + will respond with the test result. + +## Additional information +---------------------- + +- [Bot Framework SDK Schemas](https://github.com/microsoft/botframework-sdk/tree/master/schemas) +- [Create schema files](/en-us/azure/bot-service/bot-builder-dialogs-declarative) ## Docs table of contents 1. [Overview](/docs/overview.md) 2. [Extending your bot using packages](/docs/extending-with-packages.md) -3. [Extending your bot with code](/docs/extending-with-code.md) +3. Extending your bot with code (this document) 4. [Creating your own packages](/docs/creating-packages.md) 5. [Creating your own templates](/docs/creating-templates.md)