1/11/2019 Webmaster

Creating A Bot Using ChoiceFlow for Bot Builder v4 .NET SDK


ChoiceFlow is part of the Bot Builder Community Extensions project which contains various pieces of middleware, recognizers and other components for use with the Bot Builder .NET SDK v4.

This middleware component allows you to provide the user with a series of guided choice prompts, (defined in a JSON file, or as a collection of ChoiceFlowItem objects), similar to when calling a telephone line with a series of automated options.

To demonstrate this, we will create a Bot, that uses the ChoiceFlow component, that will search Help Desk Tickets in the popular open source Help Desk application ADefHelpDesk.com.

ADefHelpDesk has an API that provides the following features:

  • Requires callers to first obtain a JSON Web Token (JWT) (also called a Bearer Token), using a combination of a UserName, Password, and Application GUID. The token is then passed in the header of the subsequent requests to the other methods to authenticate the requests.
  • Allows external caller to search for Help Desk Tickets (and perform all other functionality).

image

When a user interacts with the Bot, they will be presented with questions, and depending on the method they are using to interact with the Bot, a series of cards will display the acceptable choices. Selecting a card, or entering the value in the chat input, will make the selection and move through the guided prompts.

image

The user will provide a response for the Ticket type, priority, and status to search for.

They will then be presented with the top 5 matching Tickets to their search.

Requirements

Install ADefHelpDesk

image

You can download and install ADefHelpDesk from the site at: http://ADefHelpDesk.com.

image

After you have the site running, follow the directions at the link: API Security (Swagger Rest API) on the documentation page (that can be found at this link), to create an account that can call the API.

image

You will need to copy the information on the Connection Information tab, for the API account, to use later.

image

In the ADefHelpDesk site there is a Swagger page (to learn about Swagger, see: https://swagger.io/), that documents the REST based API endpoints at: http://{your default web address}/swagger/ (for example: http://adefhelpdesk.azurewebsites.net/swagger/).

You will also want to create a few Help Desk Tickets, of various Statuses and Assignments, so that you have something to search for.

Create The Application

image

Open Visual Studio and select File, then New, then Project.

image

In the New Project dialog, select the Bot Builder Template, name the project ChoiceFlowBot and click OK.

image

The project will be created.

Hit F5 to run the project.

image

The web browser will open.

Connect Using The Bot Framework Emulator

image

Open the Bot Framework Emulator.

image

Select Open Bot.

image

Select the .Bot file that is in the root directory of the project.

image

You can now chat with the Bot.

Return to Visual Studio, and stop debugging.

Add The Nuget Package

image

The first step is to add the Bot.Builder.Community.Dialogs.ChoiceFlow NuGet package.

Right-click on the project in the Solution Explorer, and select Manage NuGet Packages.

image

Search for Bot.Builder.Community.Dialogs.ChoiceFlow and install the latest version.

Add The Models

image

Create a Models folder and add the following code files:

CustomSettings.cs

								
									namespace
									ChoiceFlowBot
								
{
								
									// This allows us to retrieve custom settings
									
								
									// from appsettings.json
								
									public
									class
									CustomSettings
								
									{
								
									public
									string
									APIWebAddress {
									get;
									set; }
								
									public
									string
									ApplicationGUID {
									get;
									set; }
								
									public
									string
									UserName {
									get;
									set; }
								
									public
									string
									Password {
									get;
									set; }
								
									}
								
}

DTOApiToken.cs

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									DTOApiToken
								
									{
								
									public
									string
									userName {
									get;
									set; }
								
									public
									string
									password {
									get;
									set; }
								
									public
									string
									applicationGUID {
									get;
									set; }
								
									}
								
}

DTOSearchParameters.cs

								
									using
									System.Collections.Generic;
								

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									DTOSearchParameters
								
									{
								
									public
									string
									searchText {
									get;
									set; }
								
									public
									string
									status {
									get;
									set; }
								
									public
									string
									priority {
									get;
									set; }
								
									public
									string
									createdDate {
									get;
									set; }
								
									public
									string
									dueDate {
									get;
									set; }
								
									public
									string
									assignedRoleId {
									get;
									set; }
								
									public
									List<int> selectedTreeNodes {
									get;
									set; }
								
									public
									string
									sortOrder {
									get;
									set; }
								
									public
									string
									sortField {
									get;
									set; }
								
									public
									int
									rowsPerPage {
									get;
									set; }
								
									public
									int
									pageNumber {
									get;
									set; }
								
									}
								
}

DTOTask.cs

								
									using
									System.Collections.Generic;
								

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									DTOTask
								
									{
								
									public
									int? taskId {
									get;
									set; }
								
									public
									int? portalId {
									get;
									set; }
								
									public
									string
									description {
									get;
									set; }
								
									public
									string
									status {
									get;
									set; }
								
									public
									string
									priority {
									get;
									set; }
								
									public
									string
									createdDate {
									get;
									set; }
								
									public
									string
									estimatedStart {
									get;
									set; }
								
									public
									string
									estimatedCompletion {
									get;
									set; }
								
									public
									string
									dueDate {
									get;
									set; }
								
									public
									int? assignedRoleId {
									get;
									set; }
								
									public
									string
									assignedRoleName {
									get;
									set; }
								
									public
									string
									ticketPassword {
									get;
									set; }
								
									public
									int? requesterUserId {
									get;
									set; }
								
									public
									string
									requesterName {
									get;
									set; }
								
									public
									string
									requesterEmail {
									get;
									set; }
								
									public
									string
									requesterPhone {
									get;
									set; }
								
									public
									int? estimatedHours {
									get;
									set; }
								
									public
									bool? sendEmails {
									get;
									set; }
								
									public
									List<int> selectedTreeNodes {
									get;
									set; }
								
									public
									List<DTOTaskDetail> colDTOTaskDetail {
									get;
									set; }
								
									}
								
}

DTOTaskDetail.cs

								
									using
									System.Collections.Generic;
								

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									DTOTaskDetail
								
									{
								
									public
									string
									taskDetailDescription {
									get;
									set; }
								
									public
									int
									detailId {
									get;
									set; }
								
									public
									string
									detailType {
									get;
									set; }
								
									public
									string
									contentType {
									get;
									set; }
								
									public
									string
									insertDate {
									get;
									set; }
								
									public
									int
									userId {
									get;
									set; }
								
									public
									string
									userName {
									get;
									set; }
								
									public
									string
									emailDescription {
									get;
									set; }
								
									public
									string
									startTime {
									get;
									set; }
								
									public
									string
									stopTime {
									get;
									set; }
								
									public
									bool? sendEmails {
									get;
									set; }
								
									}
								
}

DTOTaskList.cs

								
									using
									System.Collections.Generic;
								

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									DTOTaskList
								
									{
								
									public
									List<DTOTask> taskList {
									get;
									set; }
								
									public
									int
									totalRows {
									get;
									set; }
								
									public
									string
									errorMessage {
									get;
									set; }
								
									}
								
}

Add and Load Settings

image

Open appsettings.json and change it to the following (replacing ** Your Setting **  with your own values gathered earlier):

								
{
								
									"botFilePath": "ChoiceFlowBot.bot",
								
									"botFileSecret": "",
								
									"CustomSettings": {
								
									"APIWebAddress": "** Your Setting **",
								
									"ApplicationGUID": "** Your Setting **",
								
									"UserName": "** Your Setting **",
								
									"Password": "** Your Setting **"
								
									}
								
}

Note: For the APIWebAddress, remove the /swagger part at the end.

image

Open the Starup.cs file change all the code in the public void ConfigureServices(IServiceCollection services) method to:

								
									
										// Get the CustomSettings from appsettings.json
								
									// allow them to be passed to any class using dependency injection
								
									services.Configure<CustomSettings>(Configuration.GetSection("CustomSettings"));
								

								
									IStorage dataStore =
									new
									MemoryStorage();
								
									var conversationState =
									new
									ConversationState(dataStore);
								

								
									services.AddSingleton(dataStore);
								
									services.AddSingleton(conversationState);
								
									services.AddSingleton(new
									BotStateSet(conversationState));
								

								
									services.AddBot<ChoiceFlowBotBot>(options =>
								
									{
								
									var secretKey = Configuration.GetSection("botFileSecret")?.Value;
								
									var botFilePath = Configuration.GetSection("botFilePath")?.Value;
								

								
									var botConfig = BotConfiguration.Load(
								
									botFilePath ?? @".\BotConfiguration.bot", secretKey);
								
									services.AddSingleton(
								
									sp => botConfig ??
									throw
									new
									InvalidOperationException(
								
									$"The .bot config file could not be loaded. ({botConfig})"));
								

								
									var environment = _isProduction ? "production" : "development";
								
									var service = botConfig.Services.Where(
								
									s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault();
								
									if
									(!(service
									is
									EndpointService endpointService))
								
									{
								
									throw
									new
									InvalidOperationException(
								
									$"The .bot file does not contain an endpoint with name '{environment}'.");
								
									}
								

								
									options.CredentialProvider =
								
									new
									SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
								

								
									options.Middleware.Add(new
									AutoSaveStateMiddleware(conversationState));
								

								
									ILogger logger = _loggerFactory.CreateLogger<ChoiceFlowBotBot>();
								
									options.OnTurnError = async (context, exception) =>
								
									{
								
									logger.LogError($"Exception caught : {exception}");
								
									await context.SendActivityAsync("Sorry, it looks like something went wrong.");
								
									};
								
									});

Create The Bot Flow

image

The ChoiceFlow component uses a .json file to define the conversation flow.

The GitHub page describes the format for the .json file that you use to define the Bot.

image

Create a file called choiceFlow.json using the following code:

								
[
								
									{
								
									"name": "Top",
								
									"prompt": "What status type of Ticket would you like to search for?",
								
									"reprompt": "Choose a type from All or New",
								
									"id": 0,
								
									"choices": [
								
									{
								
									"id": 1,
								
									"name": "All",
								
									"prompt": "What Priority?",
								
									"choices": [
								
									{
								
									"id": 2,
								
									"name": "All",
								
									"prompt": "What assignment status?",
								
									"choices": [
								
									{
								
									"id": 3,
								
									"name": "All",
								
									"choices": []
								
									},
								
									{
								
									"id": 4,
								
									"name": "Unassigned",
								
									"choices": []
								
									}
								
									]
								
									},
								
									{
								
									"id": 5,
								
									"name": "High",
								
									"prompt": "What assignment status?",
								
									"choices": [
								
									{
								
									"id": 6,
								
									"name": "All",
								
									"choices": []
								
									},
								
									{
								
									"id": 7,
								
									"name": "Unassigned",
								
									"choices": []
								
									}
								
									]
								
									}
								
									]
								
									},
								
									{
								
									"id": 8,
								
									"name": "New",
								
									"prompt": "What Priority?",
								
									"choices": [
								
									{
								
									"id": 9,
								
									"name": "All",
								
									"prompt": "What assignment status?",
								
									"choices": [
								
									{
								
									"id": 10,
								
									"name": "All",
								
									"choices": []
								
									},
								
									{
								
									"id": 11,
								
									"name": "Unassigned",
								
									"choices": []
								
									}
								
									]
								
									},
								
									{
								
									"id": 12,
								
									"name": "High",
								
									"prompt": "What assignment status?",
								
									"choices": [
								
									{
								
									"id": 13,
								
									"name": "All",
								
									"choices": []
								
									},
								
									{
								
									"id": 14,
								
									"name": "Unassigned",
								
									"choices": []
								
									}
								
									]
								
									}
								
									]
								
									}
								
									]
								
									}
								
]

image

After saving the file, click on it, and in the Properties, set Copy to Output Directory to Copy always.

Create The Bot Code

image

Open the ChoiceFlowBotBot.cs file and replace all the code with the following:

								
									using
									System;
								
									using
									System.Collections.Generic;
								
									using
									System.IO;
								
									using
									System.Net.Http;
								
									using
									System.Net.Http.Headers;
								
									using
									System.Reflection;
								
									using
									System.Text;
								
									using
									System.Threading;
								
									using
									System.Threading.Tasks;
								
									using
									Newtonsoft.Json;
								

								
									using
									Microsoft.Bot.Builder;
								
									using
									Microsoft.Bot.Builder.Dialogs;
								
									using
									Microsoft.Bot.Schema;
								
									using
									Microsoft.Extensions.Logging;
								
									using
									Microsoft.Extensions.Options;
								
									using
									Bot.Builder.Community.Dialogs.ChoiceFlow;
								

								
									namespace
									ChoiceFlowBot
								
{
								
									public
									class
									ChoiceFlowBotBot : IBot
								
									{
								
									// Used to make REST calls
								
									public
									static
									HttpClient client;
								
									// To store the settings from the appsettings.json file
								
									private
									CustomSettings _CustomSettings;
								
									// Tracks Conversation State
								
									private
									ConversationState _conversationState;
								
									// Holds the collection of Dialogs
								
									private
									DialogSet Dialogs {
									get;
									set; }
								

								
									public
									ChoiceFlowBotBot(
								
									ConversationState conversationState,
								
									IOptions<CustomSettings> CustomSettings)
								
									{
								
									// Get the custom settings using dependency injection
								
									_CustomSettings = CustomSettings.Value;
								

								
									// The conversation will be tracked in _conversationState
								
									_conversationState = conversationState ??
								
									throw
									new
									ArgumentNullException(nameof(conversationState));
								

								
									// Initialize the Dialogs collection
								
									Dialogs =
								
									new
									DialogSet(_conversationState.CreateProperty<DialogState>(nameof(ChoiceFlowBotBot)));
								

								
									// Get the path to the choiceFlow.json file that contains the flow for the Bot
								
									var pathToChoiceFlowJson =
								
									Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
								
									"choiceFlow.json");
								

								
									// Use the the choiceFlow.json to create the dialogs
								
									Dialogs.Add(new
									ChoiceFlowDialog(pathToChoiceFlowJson));
								
									}
								

								
									// This method is called each time the user interacts with the Bot
								
									public
									async Task OnTurnAsync(
								
									ITurnContext turnContext,
								
									CancellationToken cancellationToken =
									default(CancellationToken))
								
									{
								
									// Get the Dialogs from the current context
								
									// This will contain a 'stack' of Dialogs as the
									
								
									// conversation progresses
								
									var dc = await Dialogs.CreateContextAsync(turnContext);
								

								
									switch
									(turnContext.Activity.Type)
								
									{
								
									case
									ActivityTypes.Message:
								
									// If we are in the middle of a dialog continue it
								
									var dialogResult = await dc.ContinueDialogAsync();
								

								
									if
									(!dc.Context.Responded)
								
									{
								
									switch
									(dialogResult.Status)
								
									{
								
									case
									DialogTurnStatus.Empty:
								
									// If we are not in the middle of a Dialog
									
								
									// start one
								
									await dc.BeginDialogAsync("MainDialog");
								
									break;
								

								
									case
									DialogTurnStatus.Waiting:
								
									break;
								

								
									case
									DialogTurnStatus.Complete:
								
									await dc.EndDialogAsync();
								
									break;
								

								
									default:
								
									await dc.CancelAllDialogsAsync();
								
									break;
								
									}
								
									}
								
									break;
								
									}
								
									}
								
									}
								
}

This sets up the shell of the code.

Essentially is initializes all the object that will be needed such as the dialogs and the conversation state. It also loads the choiceFlow.json file and creates a collection of waterfall dialog steps from it.

(Note: For more information on Dialogs, see: Using Dialogs (MS Bot Framework V4 Edition))

The code also implements the OnTurnAsync method that will be called each time the user interacts with the Bot in a conversation.

The OnTurnAsync will continue a conversation, by traversing the set of Dialogs. If it is not already in a conversation, it will start with the MainDialog.

We will create the code that will define the MainDialog in the final step.

Add The ADefHelpDesk Methods

The Bot will need to contact ADefHelpDesk to search for Tickets.

Before it can retrieve the Tickets, it needs to obtain an authorization token (also called a JSON Web Token (JWT) or Bearer Token), using the settings entered into the appsettings.json file, and injected into the class using dependency injection.

To facilitate this, add the following method to the class:

								
									private
									static
									async Task<string> GetAuthTokenAsync(
								
									string
									APIWebAddress,
								
									DTOApiToken paramApiToken)
								
									{
								
									// Store the final result
								
									string
									strResult = "";
								

								
									// Use the HttpClient
									
								
									using
									(client)
								
									{
								
									// Initialize the HttpClient
								
									client =
									new
									HttpClient();
								

								
									// Create a new REST request
								
									using
									(var request =
									new
									HttpRequestMessage())
								
									{
								
									// The Swagger page indicates this must be a "Post"
								
									request.Method = HttpMethod.Post;
								
									// Set the destination to the method indicated on the Swagger page
								
									// to: api/V1/GetAuthToken
								
									request.RequestUri =
									new
									Uri($"{APIWebAddress}api/V1/GetAuthToken");
								
									// Convert the parameters to JavaScript Object Notation (JSON) format
									
								
									var json = JsonConvert.SerializeObject(paramApiToken);
								
									request.Content =
									new
									StringContent(json, Encoding.UTF8, "application/json");
								

								
									// Make the request to the API endpoint on the ADefHelpDesk site
								
									var response = client.SendAsync(request).Result;
								

								
									// Receive the response
								
									var JsonDataResponse =
								
									await response.Content.ReadAsStringAsync();
								

								
									// Convert the response (the JWT (Auth Token)) to a String value
								
									strResult =
								
									JsonConvert.DeserializeObject<string>(JsonDataResponse);
								

								
									// Strip the word Bearer from the token
								
									strResult = strResult.Replace("Bearer
									", "
									");
								
									}
								
									}
								

								
									// Return the JWT
								
									return
									strResult;
								
									}

Now, we need to add a method, to the class, that will use the authentication token to search for Help Desk Tickets:

								
									private
									static
									async Task<DTOTaskList> SearchTasksAsync(
								
									string
									APIWebAddress,
								
									string
									paramBearerToken,
								
									DTOSearchParameters paramDTOSearchParameters)
								
									{
								
									// Store the final result
								
									DTOTaskList strResult =
									new
									DTOTaskList();
								

								
									// Use the HttpClient
									
								
									using
									(client)
								
									{
								
									// Initialize the HttpClient
								
									client =
									new
									HttpClient();
								

								
									// Create a new REST request
								
									using
									(var request =
									new
									HttpRequestMessage())
								
									{
								
									// The Swagger page indicates this must be a "Post"
								
									request.Method = HttpMethod.Post;
								
									// Set the destination to the method indicated on the Swagger page
								
									// to: api/V1/SearchTasks
								
									request.RequestUri =
									new
									Uri($"{APIWebAddress}api/V1/SearchTasks");
								
									// Pass the JWT in the 'header' of the request with the word "Bearer" in front
								
									client.DefaultRequestHeaders.Authorization =
								
									new
									AuthenticationHeaderValue("Bearer", paramBearerToken);
								
									// Convert the parameters to JavaScript Object Notation (JSON) format
									
								
									var json = JsonConvert.SerializeObject(paramDTOSearchParameters);
								
									request.Content =
									new
									StringContent(json, Encoding.UTF8, "application/json");
								

								
									// Make the request to the API endpoint on the ADefHelpDesk site
								
									var response = client.SendAsync(request).Result;
								

								
									// Handle if the JWT is expired
								
									if
									(response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
								
									{
								
									strResult.errorMessage = "Unauthorized";
								
									return
									strResult;
								
									}
								

								
									// Receive the response
								
									var JsonDataResponse =
								
									await response.Content.ReadAsStringAsync();
								

								
									// Convert the response to a String value
								
									strResult =
								
									JsonConvert.DeserializeObject<DTOTaskList>(JsonDataResponse);
								
									}
								
									}
								

								
									// Return the response
								
									return
									strResult;
								
									}

Create the MainDialog

As the final step, we will create the code that will define the MainDialog.

This defines the starting point and the ending point of the conversation.

At the end of the conversation, the code will call the GetAuthTokenAsync and SearchTasksAsync methods to search for Help Desk Tickets.

Add the following code to the end of the ChoiceFlowBotBot constructor method:

								
									Dialogs.Add(new
									WaterfallDialog("MainDialog",
									new
									WaterfallStep[]
								
									{
								
									async (dc, cancellationToken) =>
								
									{
								
									// Start the ChoiceFlowDialog that was loaded earlier
								
									// This will take the conversation through the
									
								
									// 'waterfall' steps defined in the choiceFlow.json file
								
									return
									await dc.BeginDialogAsync(ChoiceFlowDialog.DefaultDialogId);
								
									},
								
									async (dc, cancellationToken) =>
								
									{
								
									// This is called after the final step
								
									// This is called because we have run out of 'waterfall' steps
								
									// that were created when we loaded the choiceFlow.json file
								
									if
									(dc.Result
									is
									ChoiceFlowItem returnedItem)
								
									{
								
									// *******
								
									// Get a BearerToken (JWT - Auth Token)
								

								
									// Instantiate the DTOApiToken class and set the parameters
								
									// using the values from CustomSettings
									
								
									DTOApiToken paramApiToken =
									new
									DTOApiToken();
								
									paramApiToken.userName = _CustomSettings.UserName;
								
									paramApiToken.password = _CustomSettings.Password;
								
									paramApiToken.applicationGUID = _CustomSettings.ApplicationGUID;
								

								
									// Call the GetAuthToken method and retreive the BearerToken (JWT - Auth Token)
								
									string
									BearerToken = await GetAuthTokenAsync(_CustomSettings.APIWebAddress, paramApiToken);
								

								
									// *******
								
									// Use the BearerToken to search the Tickets
								
									DTOSearchParameters objDTOSearchParameters =
									new
									DTOSearchParameters();
								
									objDTOSearchParameters.pageNumber = 1;
								
									objDTOSearchParameters.rowsPerPage = 5;
								
									objDTOSearchParameters.sortField = "createdDate";
								
									objDTOSearchParameters.sortOrder = "desc";
								
									objDTOSearchParameters.createdDate = "";
								
									objDTOSearchParameters.dueDate = "";
								
									objDTOSearchParameters.searchText = "";
								
									objDTOSearchParameters.selectedTreeNodes =
									new
									List<int>();
								

								
									// Determine what the final dialog Id is
								
									int
									intFinalDialogId = returnedItem.Id;
								

								
									// Use this chart to determine what parameters to use:
								
									// (Status/Priority/Assignment Status)
								

								
									// 03 - All/All/All
								
									// 04 - All/All/Unassigned
								
									// 06 - All/High/All
								
									// 07 - All/High/Unassigned
								
									// 10 - New/All/All
								
									// 11 - New/All/Unassigned
								
									// 13 - New/High/All
								
									// 14 - New/High/Unassigned
									
								

								
									switch
									(intFinalDialogId)
								
									{
								
									case
									3:
								
									objDTOSearchParameters.status = "All";
								
									objDTOSearchParameters.priority = "All";
								
									objDTOSearchParameters.assignedRoleId = "";
								
									break;
								

								
									case
									4:
								
									objDTOSearchParameters.status = "All";
								
									objDTOSearchParameters.priority = "All";
								
									objDTOSearchParameters.assignedRoleId = "-1";
								
									break;
								

								
									case
									6:
								
									objDTOSearchParameters.status = "All";
								
									objDTOSearchParameters.priority = "High";
								
									objDTOSearchParameters.assignedRoleId = "";
								
									break;
								

								
									case
									7:
								
									objDTOSearchParameters.status = "All";
								
									objDTOSearchParameters.priority = "High";
								
									objDTOSearchParameters.assignedRoleId = "-1";
								
									break;
								

								
									case
									10:
								
									objDTOSearchParameters.status = "New";
								
									objDTOSearchParameters.priority = "All";
								
									objDTOSearchParameters.assignedRoleId = "";
								
									break;
								

								
									case
									11:
								
									objDTOSearchParameters.status = "New";
								
									objDTOSearchParameters.priority = "All";
								
									objDTOSearchParameters.assignedRoleId = "-1";
								
									break;
								

								
									case
									13:
								
									objDTOSearchParameters.status = "New";
								
									objDTOSearchParameters.priority = "High";
								
									objDTOSearchParameters.assignedRoleId = "";
								
									break;
								

								
									case
									14:
								
									objDTOSearchParameters.status = "New";
								
									objDTOSearchParameters.priority = "High";
								
									objDTOSearchParameters.assignedRoleId = "-1";
								
									break;
								

								
									default:
								
									break;
								
									}
								
								
									// Call
								
									var result = await SearchTasksAsync(
								
									_CustomSettings.APIWebAddress,
								
									BearerToken,
								
									objDTOSearchParameters);
								

								
									int
									intTopMatchingCount =
								
									(result.totalRows > 5) ? 5 : result.totalRows;
								

								
									await dc.Context.SendActivityAsync(
								
									$"Here are the top {intTopMatchingCount} matching tickets...
									" +
								
									$"The total found is {result.totalRows}");
								

								
									foreach
									(var ticket
									in
									result.taskList)
								
									{
								
									await dc.Context.SendActivityAsync(
								
									$"Ticket#{ticket.taskId} Description: {ticket.description}
									" +
								
									$"Created: {ticket.createdDate} By: {ticket.requesterName}");
								
									}
								
									}
								

								
									return
									await dc.EndDialogAsync();
								
									}
								
									}));

image

Hit F5 to run the project.

You can now converse with the Bot to search Help Desk Tickets on ADefHelpDesk.

Links

Bot Builder Community - .NET Extensions

AdefHelpDesk (Documentation)

Download

The project is available at http://aihelpwebsite.com/Downloads

You must have Visual Studio 2017 (or higher) installed to run the code.

An error has occurred. This application may no longer respond until reloaded. Reload 🗙