I'm using an external framework that defines an interface with a single method:
bool Authenticate();
that is to contain the whole process of authentication, including user interaction (WinForms). What I would like to do is something like:
bool Authenticate()
{
bool succeeded = false;
bool userCancelled = false;
while(!succeeded && !userCancelled)
{
var credentials = AskTheUserForCredentials(); // this needs to wait for user input before returning!
if (credentials == null)
userCancelled = true;
else
succeeded = AuthenticateWithAnExternalServer(credentials);
if (!succeeded)
ShowErrorMessage();
}
return succeeded;
}
Now the easy way to implement AskTheUserForCredentials() and ShowErrorMessage() is to use Form.ShowDialog() inside. This is really bad user experience, as the dialog disappears for the actual authentication process and error message appears in a new, have-to-click-to-close dialog.
I'd rather have it all in a single form, that stays visible, disables textboxes/buttons appropriately and displays the error message by itself.
How would you do it in this single, blocking method call?
UPDATE
Best solution so far is to implement a message pump inside AskTheUserForCredentials():
Credentials AskTheUserForCredentials()
{
while(NeitherOkNorCancelPressed())
{
Application.DoEvents();
Thread.Sleep(10); // Standard Sleep(0) results in 100% procesor core usage.
}
return CreateCredentialsFromTextboxesEtc();
}
Now we all know message pumps are far from clean.
Exactly how bad is this solution?
Anything better?
UPDATE 2
The message pump had some pitfalls:
being ugly and not fully cpu-effective
working terribly slow with White UIAutomation
I ended up delegating the whole process to a dialog as ChrisBD (the dialog only closes after ultimate success or failure). This took more time to abstract the authentication away from the GUI with IoC, but eventually is clean and works as intended.
I think that you're almost there.
Display a modal dialog that has the user input controls and have that dialog call the Authenticate method when required.
You can then choose when the dialog should close and indeed where any error message is displayed.
Have a property of the modal dialog class indicate whether authentication was successful or not. When you close the dialog class (which was instantiated by your main application before it opened it modally) the main application will continue to run - you can then check to see if authentication was successful or not, by checking the appropriate dialog class property.
*edited here *
If you're implementing the Authenticate method yourself then it is this function that calls the modal dialog, rather than your main application (as stated earlier). The custom form class can run all of your authentication logic and display your user interaction controls, along with any error messages. Remember to remove the minimize and close buttons and set a class property to indicate success or failure of the authentication process.
The calling framework will wait for the return value of your authentication method.
Related
I have a Windows Desktop App with an auto-update method implemented. I want to show a custom Form (because I need to change the button texts) asking the user if he or she wants to download the new version or not when a new update is detected and I want to "block" all input actions in the Desktop App until the user has made his selection.
After reading Form.ShowDialog() documentation and several topics here saying "ShowDialog() is not making my windows modal" and several answers replying "You need to properly set the owner" I still don't understand how to set this owner. Of course if I make two forms and the first one shows the second, I can "block" the first one doing:
secondForm.ShowDialog(firstForm);
But I don't know how to make that the firstForm blocks all the application to prevent the user using a deprecated version of it.
I tried several approaches like getting the current id process (or trying to get it) and convert it to IWin32Window. But nothing seemed to work.
If you need it, I add here the code I'm using:
FormAsk formAsk = new FormAsk (param1, param2);
formAsk.StartPosition = FormStartPosition.CenterParent;
formAsk.TopLevel = true;
formAsk.TopMost = true;
formAsk.DialogResult = formAsk .ShowDialog();
if(formAsk.DialogResult.Equals(DialogResult.OK))
{
// do stuff
}
else
{
// do other stuff
}
I've also seen lots of solution implementing:
myForm.ShowDialog(this);
But VS start's crying because the types are not compatible. I'm using a MVVM pattern so I can't just set a Form as an owner because I don't have a main form. Just views in .xaml and views controllers in c#.
Edit: I would like to add few comments I learned after facing this issue that may help to understand better my situation.
The main method of the program executes the following:
[STAThread]
static void Main()
{
//stuff
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
//stuff
STAApplicationContext context = new STAApplicationContext();
Application.Run(context);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Localization.Strings.error_popup_title);
Application.Exit();
}
}
}
And this context is the one that generates the service layer and views manager of the application. If I display the Forms in the service layer, showDialog() method can not "block" the input in the views but if I display them from the views (generated and handled by the view manager) i can. There's a communication between views and service, because actions triggered in the views have as consequence a service method call, but in this case the communication I want is the opposite: the service calling the methods in the view controllers to display the Forms by showDialog().
You need to pass an instance of the IWin32Window interface to the ShowDialog method.
IntPtr myWindowHandle = IntPtr(parent.Handle);
IWin32Window w = Control.FromHandle(myWindowHandle);
Do your Stuff in your first Form and whatever button you press to create your second Form just go like this. (Pseudo Code)
button1_click()
{
Form2 = new Form()
Form2.Owner = this;
}
and now from your Form2 you can talk to your Owner with this.Owner.Visible = false for example.
Thats how you make the Owner if thats what you asked for.
Thanks those who tried to help with your replies. However, although your answers probably will work in other circumstances, mine where a bit different.
Finally I achieved to solve it, I needed to do the handle with Forms in a higher level of abstraction. The information managed was retrieved from an asynchronous task so I couldn't use there a showDialog method and block the MainWindow of the application. Instead I did several threads, wait them and eventually show dialogs when I needed. It's not the best approach, but given the context is the only thing I could do.
Is there a way to verify that the page is not reloaded when click "Submit" using Selenium?
Currently the test instructs the browser to open a submit form and immediately clicks "Submit" without filling the fields.
In that way I will verify that the client side validation works and doesn't make unnecessary requests to server.
I'm using C# by the way - if it matters.
I think in this case you would have to verify the page upon submission, either the successful page or original, to determine if the form input was successful :)
Normally you would verify the error message returned on the given pop-up or sign-in form, which would lead you to conclude that the input was unsuccessful, but in this case, that doesn't seem to be possible.
Asserting the given page URI and/or page elements, will help you determine the outcome.
If only a reload check is needed, you can check for staleness of an element that was present on the page earlier. A small code example:
public bool IsNewPageLoaded(IWebElement elementToGoStale)
{
try
{
var enabled = elementToGoStale.Enabled;
return false;
}
catch(Exception ex)
{
if (ex is StaleElementReferenceException || ex is NoSuchElementException)
{
return true; // Expected exception on accessing stale element: page has been renewed
}
throw ex;
}
}
The nice thing is that you don't need any extra information about what happens after a page load: all you need is to store an IWebElement on which you can check later on.
I use similar checks in my tests. Although I still consider the try/catch part ugly, so far it has proven to be extremely reliable.
based on #Tybs 's answer, I've managed a helper class.
public class NoReloadVerificationContext : IDisposable
{
private readonly IWebElement bodyElement;
public NoReloadVerificationContext(IWebDriver webDriver)
{
this.bodyElement = webDriver.FindElement(By.TagName("body"));
}
public void Dispose() => Assert.True(this.bodyElement.Enabled);
}
I've seen such approach in some software projectes that provides API - for example creating a context that can make operation without be signed as admin until it's disposed.
An example usage:
// This block asserts that no reload occurred after executing operation inside
// Else it throws an exception - which is OK for me.
using (new NoReloadVerificationContext(driver))
{
// this will submit the form and cause page reload because of missing client vlidations
driver.FindElementByCssSelector("form input[type=submit]").Click();
} // The exception will occur here.
I don't know whether this is the best solution, but it will work in most cases (not only in forms)
The other approach was to get the value of __RequestVerificationToken inside my form (MVC generates it at the end of each form), then perform some actions, after that get the value again and compare with the old one. But this will work only for form submits.
Introduction
Currently I'm trying to create a Bot Framework application using the Microsoft Bot Framework v4.
Structure of program
We currently have the following setup:
The root of the bot class is named: SubDialogBotBot
Within the SubDialogBot we create a new Dialog named ParentDialog. This Dialog is responsible for reacting to a specific Intent.
We then start a new Dialog from the ParentDialog named ChildDialog. This child dialog will be responsible for asking the user a question based on arguments passed by ParentDialog.
After this question completed we want to return to the ParentDialog and continue the flow.
In this example we want to re-use the ChildDialog from all kinds of different intents as the code in here is exactly the same. The only thing that changes is the questions that have to be asked to the user.
Problem
When the ChildDialog completes the 'flow' is never returned to the ParentDialog.
We also tried to have the Dialog following after the ChildDialog ID set to something specific and then call this using Context.BeginDialog(....) from the ChildDialog. However because apparently the dialog was added to the ParentDialog and not to the ChildDialog it can't find this by the id.
Github repository reproducing the problem
https://github.com/devedse/SubDialogBotReproduction
First, this is an awesomely prepared question, thank you... especially for sharing the code.
Now, the good news is I don't think I see any problem with your dialogs. The problem is actually in your bot's OnTurnAsync. You are only ever calling BeginDialogAsync on your ParentDialog. Every single activity is going to come in through your OnTurnAsync and that means you're responsible for handling re-entrancy into the dialog stack. This means that, you need to check for an active dialog and, if there is one, you need to be calling ContinueDialogAsync instead to resume from where the discussion left off. Here's your current OnTurnAsync with the extra checks added:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
// Create a dialog context
var dc = await Dialogs.CreateContextAsync(turnContext);
// Handle Message activity type, which is the main activity type for shown within a conversational interface
// Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
// see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// If there's no active dialog, begin the parent dialog
if(dc.ActivDialog == null)
{
await dc.BeginDialogAsync(nameof(ParentDialog));
}
else
{
await dc.ContinueDialogAsync();
}
// Save the new turn count into the conversation state.
await _accessors.ConversationState.SaveChangesAsync(turnContext);
}
else
{
await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
}
}
I am currently developing an application in ASP.NET CORE 2.0
The following is the action inside my controller that get's executed when the user clicks submit button.
The following is the function that get's called the action
As a measure to prevent duplicate inside a database I have the function
IsSignedInJob(). The function works
My Problem:
Sometimes when the internet connection is slow or the server is not responding right away it is possible to click submit button more than once. When the connection is reestablished the browser (in my case Chrome) sends multiple HttpPost request to the server. In that case the functions(same function from different instances) are executed so close in time that before the change in database is made, other instances are making the same change without being aware of each other.
Is there a way to solve this problem on a server side without being to "hacky"?
Thank you
As suggested on the comments - and this is my preferred approach-, you can simply disable the button once is clicked the first time.
Another solution would be to add something to a dictionary indicating that the job has already been registered but this will probably have to use a lock as you need to make sure that only one thread can read-write at a time. A Concurrent collection won't do the trick as the problem is not whether this operation is thread-safe or not. The IsSignedInJob method you have can do this behind the scenes but I wouldn't check the database for this as the latency could be too high. Adding/removing a Key from a dictionary should be a lot faster.
Icarus's answer is great for the user experience and should be implemented. If you also need to make sure the request is only handled once on the server side you have a few options. Here is one using the ReaderWRiterLockSlim class.
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
This will prevent overlapping DoWork code. It does not prevent DoWork from finishing completely, then another post executing that causes DoWork again.
If you want to prevent the post from happening twice, implement the AntiForgeryToken, then store the token in session. Something like this (haven't used session in forever) may not compile, but you should get the idea.
private const SomeMethodTokenName = "SomeMethodToken";
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
var token = Request.Form.Get["__RequestVerificationToken"].ToString();
var session = Session[SomeMethodTokenName ];
if (token == session) return;
session[SomeMethodTokenName] = token
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
Not exactly perfect, two different requests could happen over and over, you could store in session the list of all used tokens for this session. There is no perfect way, because even then, someone could technically cause a OutOfMemoryException if they wanted to (to many tokens stored in session), but you get the idea.
Try not to use asynchronous processing. Remove task,await and async.
I am learning C# again after a whole lot of years. I did C# programming back in the 2.0 days. The language has indeed evolved, and its fantastic. That being said, I am making a W8/WP8 universal app. Basically when the app launches, the constructor runs a method. This method checks for a connection and if the connection is enabled, the program flows forward.
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand(
"Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));
// Show the message dialog
await msgdialog.ShowAsync();
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
So if you notice, if the connection fails then we have a message dialog popped up. There is a "try again" button the popup. When users click this button, it has a "callback function" associated with it (new stuff to me, I guess its like an event handler?). Anyways, instead of coding a new method, I made the callback method the same as the current method the messagebox is executed in. So basically what I did was added an argument so I have this UpdateInformationSection(IUICommand command). And then the callback function is the same method.
What I am scared of: Everytime they click the "try again" button, will it destroy the old instance of it? In other words, when they click the "try again" button, does the method finish executing? Otherwise I am imagining a scenario where the method is called again and again and each method is stuck in limbo (if this makes any sense).
Also, in my constructor when the method is FIRST called ,I had to change it to
//Update HUB Sections.
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);
Is it okay sending a "null" like that to the "command" argument? What is the right procedure here.
For sure, there's no true recursion here, because you are using async. But it is possible (probable, actually, but I haven't double-checked) that the MessageDialog does not complete the ShowAsync() method call until your own command delegate completes. This would result in the multiple instances of MessageDialog remaining reachable until you finally don't show it, preventing them from being garbage-collected (i.e. the closest you can get to a real memory leak with managed objects).
IMHO, the method would be better-implemented if you avoided this potential re-entrancy, by queuing the method for execution again instead of call it directly. That could look something like this:
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand("Try again"));
// Show the message dialog
await msgdialog.ShowAsync();
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
return;
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
This way, each time the MessageDialog is displayed, it's given the opportunity to go ahead and close before you redisplay it.
The above assumes "Try again" really is the only option you present. Of course, if you have additional options, you can use the UICommand object to distinguish between the selected option and do the appropriate thing; "Try again" would do the above call to RunAsync() the method again, while other options would do whatever they do.
All that said, personally I think it would be better to avoid this pattern. Presumably, the user did something else that originally initiated this dialog. At the very least, there ought to also be a "Cancel" option as an alternative to "Try Again". And IMHO it would actually be better to just present this as an alert with the default "Close", so that the user simply is taken back to wherever they were, so that after they fix the configuration issue, they can just explicitly attempt the action/operation again.
I'm of course making some assumptions about the program here. Lacking specific details, I admit there could be some compelling reason to do it the way you are now instead. But at least be sure this is really the best way to do it. Sticking a user in a potentially endless loop seems a bit "off" to me. :)
EDIT:
To elaborate on this bit of code:
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
The RunAsync() method causes the given delegate to be executed in the Dispatcher's thread, i.e. the UI thread for your program. This is where the method is already (presumably) running, since it's a command invoked by some UI object. Doing it this way allows the method to be re-invoked, but in a non-re-entrant way. I.e. the current method call is allowed to complete and return before the next one starts. This eliminates any recursive aspect.
The invoked delegate itself — () => { var ignoreTask = UpdateInformationSection(command); } — using the statement body lambda syntax, is simply the method call to invoke your command method again.
Finally, both the RunAsync() method and your command method are async methods, returning a Task instance. In this particular case, we don't need to wait for them to finish, so there's no await, but if we don't do something with the return value the compiler will generate a warning. For me, the easiest, cleanest way to suppress the warning is to go ahead and copy the Task reference to a local variable, which is enough to make the compiler happy. The RunAsync() method is copied to a variable named _, which is what I usually use for variables that I don't actually need to use, while the command method's return value is copied to a variable named ignoreTask, named that way to be explicit about the purpose of the variable (which is to ignore the Task returned from your command method).