Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Udpated extending-with-code doc #1073

Merged
merged 5 commits into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions docs/assets/MultiplyDialog.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
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);
}

/// <summary>
/// Gets the unique name of this Adaptive Dialog.
/// </summary>
[JsonProperty("$kind")]
public const string Kind = "MultiplyDialog";

/// <summary>
/// Gets or sets memory path to bind to arg1 (ex: action.arg1).
/// </summary>
/// <value>
/// Memory path to bind to arg1 (ex: action.arg1).
/// </value>
[JsonProperty("arg1")]
public NumberExpression Arg1 { get; set; }

/// <summary>
/// Gets or sets memory path to bind to arg2 (ex: action.arg2).
/// </summary>
/// <value>
/// Memory path to bind to arg2 (ex: action.arg2).
/// </value>
[JsonProperty("arg2")]
public NumberExpression Arg2 { get; set; }

/// <summary>
/// Gets or sets caller's memory path to store the result of this step in (ex: dialog.result).
/// </summary>
/// <value>
/// Caller's memory path to store the result of this step in (ex: dialog.result).
/// </value>
/// <remarks>
/// This is where the result of the Dialog is stored and accessible in Composer.
/// </remarks>
[JsonProperty("resultProperty")]
public StringExpression ResultProperty { get; set; }

/// <summary>
/// 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.
/// </summary>
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);
}
}
}
27 changes: 27 additions & 0 deletions docs/assets/MultiplyDialog.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PackageId>CustomAction.MultiplyDialog</PackageId>
<Description>This library implements .NET support for the MultiplyDialog custom action sample BotComponent.</Description>
<Summary>This library implements .NET support for the MultiplyDialog custom action sample BotComponent.</Summary>
<ContentTargetFolders>content</ContentTargetFolders>
<!--<PackageTags>msbot-component;msbot-action;msbot-trigger</PackageTags>-->
<PackageTags>msbot-component;msbot-action</PackageTags>
</PropertyGroup>

<ItemGroup>
<Content Include="**/*.dialog" />
<Content Include="**/*.lg" />
<Content Include="**/*.lu" />
<Content Include="**/*.schema" />
<Content Include="**/*.uischema" />
<Content Include="**/*.qna" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive.Runtime" Version="4.13.1" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions docs/assets/MultiplyDialog.schema
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
33 changes: 33 additions & 0 deletions docs/assets/MultiplyDialogBotComponent.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Definition of a <see cref="Microsoft.Bot.Builder.BotComponent"/> that allows registration of
/// services, custom actions, memory scopes and adapters.
/// </summary>
/// 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
{
/// <summary>
/// Entry point for bot components to register types in resource explorer, consume configuration and register services in the
/// services collection.
/// </summary>
/// <param name="services">Services collection to register dependency injection.</param>
/// <param name="configuration">Configuration for the bot component.</param>
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));
}
}
}
158 changes: 147 additions & 11 deletions docs/extending-with-code.md
Original file line number Diff line number Diff line change
@@ -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:/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 `<ProjectReference Include="..\MultiplyDialog\MultiplyDialog.csproj" />` 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:/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)