How to remove tooManyAttempts message in Prompt.Choice? How to accept text in Prompt.Choice that is not in list of options? C# - botframework

I'm using bot-Framework SDK3 C#.
I want to allow user input anything which is not in "PromptDialog.Choice"'s options. Any better ways to recommend?
This is my code.
private async Task SelectCategory(IDialogContext context)
{
List<string> options = new List<string>();
options = category.Keys.ToList();
options.Add("Category1");
options.Add("Category2");
options.Add("Category3");
PromptOptions<string> promptOptions = new PromptOptions<string>(
prompt: "which one do you prefer?",
tooManyAttempts: "",
options: options,
attempts: 0);
PromptDialog.Choice(context: context, resume: ResumeAfterSelectCategory, promptOptions: promptOptions);
await Task.FromResult<object>(null);
}
private async Task ResumeAfterSelectCategory(IDialogContext context, IAwaitable<string> result)
{
try
{
selected = await result;
}
catch (Exception)
{
// if the user's input is not in the select options, it will come here
}
}
But the problem is it always send the message "tooManyAttempts". If I set it to empty, I will send me "0".

I suppose you are using NodeJS. You can use the simple builder.Prompts.choice with maxRetries set to 0. Here is a sample snippet. It asks user to choose some option from a list, or they can enter something which is not in the list.
If you are using C# SDK, you can find some similar option for the list.
bot.dialog("optionalList", [
function(session){
builder.Prompts.choice(
session,
"Click any button or type something",
["option1", "option2", "option3"],
{maxRetries: 0} // setting maxRetries to zero causes no implicit checking
)
},
function(session, result){
// something from the list has been clicked
if(result.response && result.response.entity){
console.log(result.response.entity); // use the clicked button
} else {
console.log(session.message.text) // if user entered something which is not in the list
}
}
]);
EDIT 1:
Hi, Saw that you are using C# SDK. I am not that proficient with that but I can give you some suggestion.
The list which you generate in the async task SelectCategory you can generate in some other place, which is also accessible to the second async task ResumeAfterSelectCategory, (like making it a class variable or getting from database).
Now that the list is accessible in the 2nd task, you can compare what user has typed against the list to determine if the message is from the list or not.
If message is something from the list, then take action accordingly, otherwise user has entered something which is not in the list, and then take action accordingly.
Your 2nd problem is
And if user typed, it will show a message "you tried to many times"
What is meant by that? Does bot sends "you tried to many times" to the bot visitor. In which case it could be the behavior of library. You will be able to control that only if library provides some option. Else I don't know. Hope, that helps
EDIT 2:
I came across this SO question Can I add custom logic to a Bot Framework PromptDialog for handling invalid answers?
You can use that questions answer. Basically extending PromptDialog.PromptChoice<T>.Here is an example.
Override TryParse method like this
protected override bool TryParse(IMessageActivity message, out T result)
{
bool fromList = base.TryParse(message, out result);
if (fromList)
{
return true;
} else {
// do something here
return true; // signal that parsing was correct
}
}

I used node.js and to get message which user entered. use this code snippet.
(session, args) => {
builder.Prompts.text(session, "Please Enter your name.");
},
(session, args) => {
session.dialogData.username = args.response;
session.send(`Your user name is `${session.dialogData.username}`);
}

Related

How can I call an async method when a button is clicked and avoid warning messages for message not returning void?

Here's the code that I have.
The IDE is giving me a warning line under the "async" in the 3rd line, that says "Asynchronous method must not return void"
public QHPageViewModel()
{
DeleteQuizCmd = new Command<string>(async (x) => await DeleteQuizAsync(x));
}
private async Task DeleteQuizAsync(string quizId)
{
var canContinue = await Shell.Current.DisplayAlert("Delete Quiz", "Do you want to delete the results for Quiz " + quizId, "OK", "Cancel");
if (canContinue == false)
return;
App.DB.DeleteQuizHistory(System.Convert.ToInt32(quizId));
UpdateQuizDetails();
}
Is there an issue with the way that this is coded, is there a better way to code this or should I just ignore this message? What are the consequences of ignoring the message?
It yells at you cause basic XF Commands don't have async capabilities.
If you want warnings to go away, you can write your own AsyncCommand implementing ICommand, or just use the AsyncCommand from stephen cleary: https://github.com/StephenCleary/Mvvm.Async/tree/master/src/Nito.Mvvm.Async
To avoid any warning, and keep the same logic you can also write:
if (await Shell.Current.DisplayAlert("Delete Quiz", "Do you want to delete the results for Quiz " + quizId, "OK", "Cancel"))
{
App.DB.DeleteQuizHistory(System.Convert.ToInt32(quizId));
UpdateQuizDetails();
}

Is there a way to use ChoicePrompt without validating choices?

I would like to present the user with a series of choices, but also allow them to type in freeform text. The Choice prompt will automatically reprompt until a choice or synonym is chosen.
The RecognizerOptions NoValue and/or NoAction appear to be related to this, but I haven't been able to find good documentation on them. Setting them to true doesn't work.
AddDialog(new ChoicePrompt(promptForChoice) { RecognizerOptions = new FindChoicesOptions() { NoValue = true, NoAction = true } });
I've also tried creating an "anything" validator that always returns true.
AddDialog(new ChoicePrompt(promptForChoice, validator: AnythingValidator.AnythingValidatorAsync) { RecognizerOptions = new FindChoicesOptions() { NoValue = true, NoAction = true } });
public static Task<bool> AnythingValidatorAsync(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
return Task.FromResult(true);
}
This allows the prompt to exit, but the result is null. I can go dig out what the user entered from the Context.Activity.Text but that doesn't seem like a very robust solution.
There seems to be something obvious I'm missing with PromptChoice
Choices work by hardcoding in the options the user needs to choose from. We can't implement freeform text in choices. What you can do is, add another choice "others" in the choice list and implement a waterfall to get the user input. Also, you can't use the RecognizerOptions as they are related to synonyms.

What's the difference between these two nservicebus statements

In one documentation they say IHandleMessages handler hast to be written this way (signature is automatically generated when I choose to "Implement interface" option in Visual Studio):
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
return context.Publish(orderPlaced);
}
}
While another documentation says it has to be written this way:
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public async Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
await context.Publish<OrderPlaced>(e => { e.OrderId = message.OrderId; });
}
}
I wonder what is the difference between these two statements, can someone explain in simple language?
Which option is the right one?
Both are correct options. The difference between the two is how a single asynchronous operation is handles in the Handle method.
In the first case, a Task is returned as-is. In the second case, publishing is awaited within the Handle method. The difference? In the first case no async state machine is created by the compiler as the task of publishing returned back. In the second scenario, a state machine is created.
Which option is the right one to use? They are both correct options. If a method is called frequently and you care for the unnecessary allocations not to take place, returnng a single task without awaiting is more efficient.

how to get access to current MessageActivity from PromptDialog choice in BotFramework

I'm presenting the user with 4 choices via the PromptDialog.choice method. In my Resume method, I want to forward the user to a dialog to handle their choices. I no longer have access to the current MessageActivity object
and wonder what my options are? I'd like to pass the original Message if at all possible. Passing an empty one seems like a hack. And the dialog PrintGraphicDialog will just display a graphic image and return back to the 4 choices. using Context.Call hits the PrintGraphicDialog's StartAsync method and has the context.wait() call which requires the user to type something. Then it prints the graphic. Not quite what is wanted either.
private void ShowOptions(IDialogContext context)
{
PromptDialog.Choice(context, this.OnOptionSelected, new List<string>() { OptionOne, OptionTwo, OptionThree, OptionFour }, "Please select from the following options:", "Not a valid option", 3);
}
private async Task OnOptionSelected(IDialogContext context, IAwaitable<string> result)
{
try
{
string optionSelected = await result;
switch (optionSelected)
{
case OptionOne:
await context.Forward(new PrintGraphicDialog(), this.ResumeAfterOptionDialog, context.MakeMessage(), CancellationToken.None);
break;
case OptionTwo:
break;
case OptionThree:
break;
case OptionFour:
break;
}
}
catch (TooManyAttemptsException ex)
{
}
}
You can store the message in a variable right before calling your PromptDialog.Choice and then use it in the Resume method.
Since the dialog I was forwarding control to really only needs a few properties from the original message, I just created a class, stored them in there and before forwarding, did context.MakeMessage() and populated that with the stored off properties. Seems like there should be a better way.

howto create a confirm dialog in windows phone 7?

How can I create a confirm dialog in windows phone 7?
I have an app in which I can delete items, but when someone clicks delete, I want to get him a confirm dialog where they can click 'confirm' or 'abort'
How could I do this?
you can use this:
if(MessageBox.Show("Are you sure?","Delete Item", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
//Delete Sentences
}
Shows a dialog something like this:
Here is the method I use. By the way for a better user experience and for consistencies sake consider using the words "delete" and "cancel" rather than "confirm" or "abort".
public static MessagePromptResult Show(string messageBoxText, string caption, string button1, string button2)
{
int? returned = null;
using (var mre = new System.Threading.ManualResetEvent(false))
{
string[] buttons;
if (button2 == null)
buttons = new string[] { button1 };
else
buttons = new string[] { button1, button2 };
Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
caption,
messageBoxText,
buttons,
0, // can choose which button has the focus
Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.None, // can play sounds
result =>
{
returned = Microsoft.Xna.Framework.GamerServices.Guide.EndShowMessageBox(result);
mre.Set(); // could have done it all without blocking
}, null);
mre.WaitOne();
}
if (!returned.HasValue)
return MessagePromptResult.None;
else if (returned == 0)
return MessagePromptResult.Button1;
else if (returned == 1)
return MessagePromptResult.Button2;
else
return MessagePromptResult.None;
}
You will need to add a reference to Microsoft.Xna.Framework.GamerServices to your project.
Rather than asking the user to confirm deletion, have you considered giving the user the ability to "un-delete" items?
While this may be a little bit more work, when it makes sense in teh context of the app it can lead to a much better user experience.
If OK / Cancel is good enough for you, you could stick to the regular MessageBox.Show

Resources