how to get access to current MessageActivity from PromptDialog choice in BotFramework - 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.

Related

What to use instead of Exceptions when writing validation code?

I am writing some validation code and am not sure how to pass validation messages back to the calling code.
Exceptions come to mind, but I think that Exceptions should not be used in user input validation. As #Blowdart puts it:
Exceptions are not
control flow mechanisms. Users often get passwords wrong, it's not an
exceptional case. Exceptions should be a truly rare thing,
UserHasDiedAtKeyboard type situations.
From: https://stackoverflow.com/a/77175/125938. I'm extending that sentiment to all "incorrect" user input that a user might enter.
So the question is what to use instead of Exceptions. For certain situations, I could just use an IsValid… method that returns a bool for validity, but what if I want to pass an error message back with it? Should I create a custom "ValidationError" object, with a Message property? What makes sense and causes Least Astonishment (preferably a tried and tested pattern)?
If I were to do this in a truly object-oriented way, I'd adhere to the separation of concerns principle and compose a chain of classes that each deal with a separate step on the input - validation - output journey.
Let's say we are parsing a date from string as entered by the user.
My first class would encapsulate the raw value and attempt to parse the date (pseudo-code):
class TextualDate {
public TextualDate(string value) {
// just initialize with the provided value
}
public Option<Date> AsDate() {
// try parsing and either return the date or not
// the Option<Date> type is here to suggest that the conversion might not succeed
}
}
Next I'd have a validation class that instantiates the TextualDate class, invokes its AsDate() method and returns the validation result:
class ValidatedDate {
public ValidatedDate(TextualDate value) {
// initialize with the provided value
_textualDate = value;
}
private TextualDate _textualDate;
public ValidationResult Validated {
var maybeDate = _textualDate.AsDate();
// see whether we have a date or not
return new ValidationResult(...);
}
}
In our ValidationResult class, we might find some status property (OK, Failed), any error message either provided directly or as a key to then look-up in a message catalog etc.
This way, we can isolate concerns and only deal with the error messages on the UI layer while being able to use and reuse the validation logic independently.
I was faced with a similar dilemma in the past - I had to write a couple of services that takes data from a 3rd party, manipulating it in various ways, and send that data to other services for further processing.
All of these services might have failed because of wrong or incomplete data, but it was nor unexpected neither exceptional - and I refused to use exceptions for these cases.
I've done an extensive research, reading anything I could get my hands on in this subject in two days, and finally decided the following:
A method might need to return data and might not (sub in Visual Basic, void in Java/C#) - but in both cases, I wanted an indication for success/fail and a potential error message.
If your language of choice supports tuples, you could return a tuple from your methods:
public (bool Success, string ErrorMessage) DoSomething()
{
// implementation here
}
or
public (bool Success, someType Value, string ErrorMessage) DoSomething()
{
// implementation here
}
If not, you can do what I did (That was c#5 - so no value tuples) and create a result class:
public class Result
{
public static Result Success()
{
return new Result(true, null);
}
public static Result Fail(string errorMessage)
{
return new Result(false, errorMessage);
}
protected Result(bool success, string errorMessage)
{
Success = success;
ErrorMessage = errorMessage;
}
public bool Success {get; private set;}
public string ErrorMessage {get; private set;}
}
public class Result<T>
{
public static Result<T> Success(T value)
{
return new Result(true, null, value);
}
public new static Result<T> Fail(string errorMessage)
{
return new Result(false, errorMessage, default(T));
}
private Result<T>(bool success, string errorMessage, T value)
: base(success, errorMessage)
{
Value = value;
}
public T Value {get; private set;}
}
And use it like this:
public Result CouldBeVoid()
{
bool IsOk;
// implementation
return IsOk ?
Result.Success() :
Result.Fail("Something went wrong") ;
}
public Result<int> CouldBeInt()
{
bool IsOk;
// implementation
return IsOk ?
Result.Success(intValue) :
Result.Fail("Something went wrong") ;
}
var result = CouldBeVoid();
if(!result)
// do something with error message
var result = CouldBeInt()
if(result)
// do something with int value
else
// do something with error message
Users often get passwords wrong, it's not an exceptional case.
Yes and no. Whether to throw an exception or not depends on the question you're asking. And in the course of logging a user in, there are typically quite a number of questions being asked before you come to the conclusion whether the user can be logged in or not. The more you break down your code into specialised parts, the more it may make sense to raise exceptions in some of those parts.
Say you specify your login procedure the following way in an HTTP context:
Get the username* and password* from the request.
Fetch the user record* by its username from the database*.
Check whether the record's password* equals* the entered password.
If yes, start a session.
If any of the above steps do not successfully complete, output an appropriate error message.
Any of the items marked with an asterisk above may fail:
The request may not contain a username or password.
There may not be a user record for this username, or the database may be down.
For whatever reason, the record may not have a password and/or be corrupted. The stored password may, for whatever reason, use an unsupported hashing algorithm and hence can't be compared.
It should be rather obvious that in this process there are any number of cases that would be ideal to be implemented as an exception. The actual function which tests the password should probably not throw an exception in case the password is merely false; that should be a boolean return value. But it may still throw an exception for any other number of reasons. If you use exceptions properly, you'll end up with code that looks something like this (pseudo-pseudo code):
try {
username = request.get('username')
password = request.get('password')
user = db.get(username=username)
if (user.password.matches(password)) {
session.start()
} else {
print 'Nope, try again'
}
} catch (RequestDoesNotHaveThisDataException) {
logger.info('Invalid request')
response.status(400)
} catch (UserRecordNotFoundException) {
print 'Nope, try again'
} catch (UnsupportedHashingAlgorithmException, PasswordIsNullException) {
logger.error('Invalid password hash for user ' + user.id)
response.status(500)
print 'Sorry, please contact our support staff'
} catch (DatabaseDownException e) {
// mostly for illustration purposes,
// this exception should probably not even be caught here
logger.exception('SEND HALP!')
throw e
}
So, yes, this is a very simple process, but literally every step along the way has one or more exceptional cases. You ask the question "what is the username the user sent in the request?", and if there's no answer to this question because the user didn't sent any username, you have an exceptional case. Exceptions simplify control flow here a lot as opposed to trying to cover each of these cases with an if..else.
It is NOT an exception if the username is not valid or the password is not correct.
(From the answer you quote from.)
As you can see, we're testing whether the username is "valid" or not by trying to fetch its record from the database. If we have a function whose purpose is to fetch records of users from the database, and there is no such record, then an exception is an entirely valid response. If we defined that function to test whether such a record exists and null or false is a valid return value… fine. But in this case we didn't write it that way, and frankly, that results in simpler control flow I find.
Now, only the password validation itself does not use an exception, since the question asked there is "does this password match that password?", to which the answer can clearly be yes or no. Again, only if something exceptional like an unsupported hashing algorithm turns up can there be no answer to this question and an exception is entirely warranted.
Having said all this, you may notice that most of these cases, except the really fatal one with the database, does not outwardly result in an exception. The component here is expecting and handling certain cases that its sub-components regard as exceptional. This code here is asking the questions, and is prepared to handle Mu as an answer for some of them. Which is to say, a general rule that says "exceptions shouldn't be used in process X, Y or Z because it's not exceptional enough" is too dogmatic. It depends on the purpose of each individual piece of code whether an exception is warranted or not.
Having said all this, what you're asking about is some sort of form validation. The above code shows a case where two pieces of data may each be invalid, and it's using exceptions to in the end still result in a "yes" or "no" response. You can of course encapsulate that in an object like this:
val = new LoginFormValidator()
val.setDataFromRequest(request)
val.validate()
if (val.isValid) {
print 'Hurray'
} else {
print 'You have errors:'
for (error in val.errors) {
print error.fieldName + ': ' + error.reason
}
}
Whether this validator uses exceptions internally for any of this you do not need to care, but in the end it saves all of them as a "yes" or "no" result to its internal properties, from where you can take them either as an aggregate (val.isValid) or individually (for (error in val.errors)).

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

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}`);
}

Data Fetching Crashes in Xamarin Forms

I am trying to fetch Customer data to parse them into customer object to display on TableView. The following code sometimes works, sometimes not. Whenever it does crash, it shows Customer data is empty in the foreach loop even though I run the same code every time. I do not have clue what could be wrong in this circumstances. I am quite new on this platform. If I am missing anything/ extra information, please let me know.
namespace TableViewExample
{
public partial class MyDataServices : ContentPage
{
private ODataClient mODataClient;
private IEnumerable <IDictionary<string,object>> Customers;
public MyDataServices ()
{
InitializeComponent ();
InitializeDataService ();
GetDataFromOdataService ();
TableView tableView = new TableView{ };
var section = new TableSection ("Customer");
foreach (var customers in Customers) {
//System.Diagnostics.Debug.WriteLine ((string)customers ["ContactName"]);
var name = (string)customers ["ContactName"];
var cell = new TextCell{ Text = name };
section.Add (cell);
}
tableView.Root.Add (section);
Padding = new Thickness (10, 20, 10, 10);
Content = new StackLayout () {
Children = { tableView }
};
}
private void InitializeDataService(){
try {
mODataClient = new ODataClient ("myURL is here");
}
catch {
System.Diagnostics.Debug.WriteLine("ERROR!");
}
}
private void GetDataFromOdataService (){
try {
Customers = mODataClient.For ("Customers").FindEntries ();
}
catch {
System.Diagnostics.Debug.WriteLine("ERROR!");
}
}
}
}
Its hard helping out here, however here are some things to consider:-
It sounds like the dataservice could either be not contactable / offline; too busy or it could even be throwing an exception itself and returning a data response that you are not expecting to receive, that then triggers an exception and crash in your application as your always expecting an exact response without catering for any abnormal responses / events.
If you are contacting an external service over the internet it may just be your internet connection is slow / faulty and not returning the information fast enough as other possibilities.
In your code you are assuming that you always get a response from the server - and that this response will always be of an anticipated structure that your expecting to decode - without factoring in any possibility of abnormal responses returned by the dataservice. I have not used ODataClient personally, so not sure how it behaves in the event of maybe no data received / timeout or in your case the dataservice and how it behaves internally in the response to a bad-request etc.
I am assuming an exception would get thrown, and you do get your debug line executed indicating a failure.
You may want to also adjust this statement so that you write out the exception as well, i.e.:-
private void GetDataFromOdataService ()
{
try
{
Customers = mODataClient.For ("Customers").FindEntries ();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("ERROR!" + ex.ToString());
}
}
If there was a bad response, then the line at Customers = ..... would throw the exception as there may be no Customers returned or some other information packaged in the response from the dataservice.
The Customers variable would also be null at this point I am assuming due to this failing.
So when you get back to your code at foreach (var customers in Customers) { it will then throw a null reference exception as Customers is infact null.
As all your current code executes in the constructor without any try and catch block around this, it will also crash your application at this point as well.
Also you are doing all of this work in the constructor. Try seperating this out. I haven't investigated exactly where the constructor gets called in an iOS page life-cycle, however, if it is in the viewDidLoad, then you have something like 10 seconds for everything to complete, otherwise it will exit automatically. I imagine in your case, this isn't applicable however.
Going forward also try putting your layout controls in the constructor, and move your data task to maybe the OnAppearing override instead.
Using async would definitely be advisable as well, but remember you need to inspect the response from your dataservice, as the error could be embedded within the response also and you will need to detect when it is OK to process the data.

Windows phone 7: facing issue for passing parameters

Right now i am developing a Windows phone app, yes this is my first windows app. Right now i am facing an issue, don't know what's the silly mistake i made. Yes of course i have done debugging.
Now, what exactly i am doing?
Passing data from 1st page to 2nd page,
On the page, catching data inside onNavigateTo() method, yes i am receiving it correctly.
Based on the parameter/data (i.e. ID) i got, i am making web service call.
Problem:
If i move to the 3rd page from 2page and again came back to the 2nd page, its again making web call. i.e. calling DownloadStringAsync again in below code.
i.e. If 2nd page is having ListBox with 5 data, now clicking on particular item i am moving to 3rd page, if i came back to 2nd page from page 3, items get doubled i.e. 10 items (just because its making call again)
Here is the possible code for the reference:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
type = Convert.ToInt32(NavigationContext.QueryString["Type"]);
if (type != 0)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
client.DownloadStringAsync(new Uri(Utils.Constant.WebService_URL));
}
else
{
MessageBox.Show("Please check internet connection!!");
}
}
}
Can't you use the following code to test if the user used the back button?
e.NavigationMode == System.Windows.Navigation.NavigationMode.Back
sometimes this method(QueryString) create problems.
In back event it create problems
its betters to store the id(parameter) in isolatedstorage application key
IsolatedStorageSettings.ApplicationSettings["id"] = "your data";
OnNavigatedTo is called whenever you navigate to the page, either by a forward navigation, or a back navigation. That's why it's retriggered when you navigate back from page #3 to page #2.
You can avoid this by only triggering the network call on a forward navigation.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (this.isInitialized) return;
type = Convert.ToInt32(NavigationContext.QueryString["Type"]);
if (type != 0)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
client.DownloadStringAsync(new Uri(Utils.Constant.WebService_URL));
}
else
{
MessageBox.Show("Please check internet connection!!");
}
}
this.isInitialized = true;
}
Beware that NetworkInterface.GetIsNetworkAvailable can block (in this case the UI thread) for a long time in some scenarios, to work around this you can use network detection events.

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