I need to implement the following: I have a page on which user enters an email. Every time text changes, I have to check whether the user exists in a DB and based on that information, I should set the text of the button to either "Sign up" or "Sign in". The problem is, that this DB request may take a couple of seconds (the reason is irrelevant) and the API is async, so event handler will be decorated with async, and since mail entry may change several times, this handler will be called several times before any one will end. So I'll have concurrent API requests and then, potentially, concurrent attempts to change the button text and that may not end well. I thought of something like this:
private async void OnTextChanged(object sender, TextChangedEventArgs e)
{
mailEntry.TextChanged -= OnTextChanged;
...
submitButton.Text = (await api.AccountExistAsync(mailEntry.Text)).IsRegistered
? "Sign in"
: "Sign up";
...
mailEntry.TextChanged += OnTextChanged;
}
But a problem with this design, is that, say, a valid email was entered between -= OnTextChanged and += OnTextChanged, in which case it'll never be checked.
My question is, what is the right way to implement what I'm trying to achieve? Thanks in advance.
Here is one solution:
private long requestNumber;
private async void OnTextChanged(object sender, TextChangedEventArgs e)
{
var text = mailEntry.Text;
long myRequestNumber = ++requestNumber;
await Task.Delay(200);
if (requestNumber != myRequestNumber)
return;
var result = (await api.AccountExistAsync(text)).IsRegistered;
if (requestNumber != myRequestNumber)
return;
submitButton.Text = result ? "Sign in" : "Sign up";
}
It maintains a requestNumber variable to hold the last request number which is incremented each time you change the text.
If after the AccountExistAsync operation completes the code discovers that the variable was changed, it will conclude that a new request has been issued, and will not update the UI.
Please note that the solution also waits 200 milliseconds before attempting to send a validation request. Although this will delay the validation operation 200 milliseconds, it will prevent too many requests to be sent, especially as the user is typing quickly. This is optional of course.
Edit:
I removed the use of synchronization when reading/updating requestNumber because such code runs in the UI thread only.
Related
I'm working on a really big project developed by two teams, one (mainly) for the database, and one (where I am) mainly for the GUI and helper classes as an interface between GUI and DB.
Obviously, there are errors in communication, and - of course - we can't assume 100Mbit bandwidth & super-fast server computer.
Language is C# .NET, target "framework" is WPF and Silverlight.
When a user clicks a button, the GUI asks the DB (through helper classes) for information. Let's say... pizza types. The server should answer "{Funghi,Frutti di mare,Prosciutto}". When DB sends his answer, we receive a "database.Ready" event and fill our datagrid.
BUT if the user clicks the button while we haven't received the answer yet, the GUI sends an another request to the database. And the whole system tries to serve the user.
But it can't, because when the second request is sent, the first is disposed when we want to read it. So NullReferenceExceptions occur.
I've solved this by implementing kind of a semaphore which closes when user input occurs and opens when the Ready event (the functions it calls) finishes working.
Problem:
If I don't receive the Ready event, no user input is allowed, but this is wrong.
Question:
Is there a common (or at least, working) solution to stop waiting for the Ready event and...
1) re-sending the request a few times, hoping we receive our pizza types?
AND/OR
2) Dropping the request, tell the user that database failed to send the answer, and re-open the semaphore?
I can't post code here as this code is the property of a corporation, I'd rather like to have theoretical solutions, which are okay for professionals too.
Sorry for the long post, and thank you for your answers!
I assume that you are already using a background thread to dispatch the query to the database and wait for it's response. You can use the Task API that was introduced in .NET 4.0 to cancel such a request. For that, you pass in a CancellationToken that signals the status to the executing task. You can obtain a CancellationToken via a CancellationTokenSource as shown in the following code:
public partial class MainWindow : Window
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public MainWindow()
{
InitializeComponent();
}
private void Button_CallDatabase(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(CallDatabase, _cancellationTokenSource.Token);
}
private void Button_OnNavigate(object sender, RoutedEventArgs e)
{
// If you navigate, you can cancel the background task and thus
// it will not execute any further
_cancellationTokenSource.Cancel();
}
private void CallDatabase()
{
// This simulates a DB call
for (var i = 0; i < 50; i++)
{
Thread.Sleep(100);
}
// Check if cancellation was requested
if (_cancellationTokenSource.Token.IsCancellationRequested)
{
Debug.WriteLine("Request cancelled");
return;
}
Debug.WriteLine("Update Controls with DB infos.");
}
}
Note that this example is simplified, you can and should use this in another component (e.g. view model).
If you still want to use the Ready event, you could also just unregister from it when you navigate away, so that no further actions will be performed when it is raised.
I am not really sure how thread works.
Here is my code. Upon clicking a send button:
protected void BtnSend_Click(object sender, EventArgs e)
{
Thread threadA = new Thread(SendSMS);
threadA.Start();
}
protected void SendSMS()
{
//some validations here
Thread threadB = new Thread(loadingScreen);
threadB.Start();
threadB.Join();
//code that actually sends the required Mail
threadB.Stop();
loading.Visible = false;
}
threadB is calling this method which is basically a div (called loading) with a loading div that disables user from pressing anything on screen:
protected void loadingScreen()
{
loading.Visible = true;
}
Now the mail is being sent but the loading screen (div) is not becoming visible.
What am I doing wrong?
You have to rethink when you're writing ASP.NET vs. a rich client application. In short (really really short) the web browser (client) sends a request to the server. The server handles that request (that part is your code behind), and returns a result to the web browser.
When you show a DIV in your codebehind, do some work, then hide it again, only the result will arrive at the web browser.
There are multiple ways to achieve the optical effect you want, but you must know about the Life Cycle of ASP.NET first. Start here, for example.
I think you want a responseable application while you compute a huge task.
In WinForms you have to be careful because if you want to change some UI like a Text in a Label you have to synchronize both Threads. (UI-Thread and Thread1)
If you are running .NET 4.0 you should use the Task-Class, because there you don't need to synchronize and you can also use anonymous methods.
protected void SendSMS()
{
loading.Visible = true;
var task = Task.Factory.StartNew(()=>{//code that actually sends the required Mail}
task.Wait();
loading.Visible = false;
}
Actually the loading Gets visible and then hidden quickly. Join returns immediately as soon as it enabled the Div and then the email is sent, the Div is disabled again. Sending email and disabling happens in same thread.
Why do you use threadB? You can do operation only with threadA:
protected void SendSMS()
{
//some validations here
loading.Visible = false;
//code that actually sends the required Mail
loading.Visible = false;
}
Warning for crossthread operation exception.
This has been asked before here, but the answer there was simply "use BackgroundWorker", and I'm asking if there is a complete code sample available.
I'd like to create a standard AutocompleteTextBox that works with a timer, such that there is only one BackgroundWorker working on searching - if the user entered a few more keystrokes, but the old search is still running - that search shall be canceled gracefuly (via CancelAsync), and as soon as its canceled the new search will begin.
This is not so trivial to implement - are there any code samples of this?
I doubt you'll find a code sample that helps you with the specific issues you're talking about here. Here's how I'd do this. None of this code is tested, so beware of stupid bugs.
First, subclass TextBoxBase and add two basic methods to implement the search logic, with the following signatures:
private IEnumerable<string> PerformSearch(string text)
private DisplayResults(IEnumerable<string> results)
Add a private BackgroundWorker field named Worker to the class and set its DoWork and RunWorkerCompleted events to event handlers named Worker_DoWork and Worker.RunWorkerCompleted.
Override OnTextChanged:
public override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
// if we're already cancelling a search, there's nothing more to do until
// the cancellation is complete.
if (Worker.CancellationPending)
{
return;
}
// if there's a search in progress, cancel it.
if (Worker.IsBusy)
{
Worker.CancelAsync();
return;
}
// there's no search in progress, so begin one using the current value
// of the Text property.
Worker.RunWorkerAsync(Text);
}
The Worker_DoWork event handler is pretty simple:
private void Worker_DoWork(object sender,
RunWorkerCompletedEventArgs e)
{
e.Result = PerformSearch((string) e.Argument);
}
The Worker_RunWorkerCompleted event handler looks something like this:
private void Worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
// always check e.Error first, in case PerformSearch threw an exception.
if (e.Error != null)
{
// in your version, you want to do real exception handling, not this.
throw e.Error.InnerException;
}
// if the worker was cancelled, it's because the user typed some more text, and
// we want to launch a new search using what's currently in the Text property.
if (e.Cancelled)
{
Worker.RunWorkerAsync(Text);
return;
}
// if the worker wasn't cancelled, e.Result contains the results of the search.
DisplayResults((IEnumerable<string> e.Result);
}
Note that DisplayResults should test any assumption it makes about the state of the text box. The text box may have been visible or enabled when the user launched the search and not be visible or enabled now, for instance. What happens if you use this text box in a modal dialog and the user cancels the dialog while the search is running?
Note also that if you have multiple instances of this control in your application, each one will have a different BackgroundWorker, so it's important that the PerformSearch method be thread-safe. If it's not, it will have to implement locking, so that if you launch a search in one text box it blocks and waits if another text box is currently using the shared resource.
I suggest using the AutoComplete feature in System.Windows.Forms.TextBox. You can customize it and build your completion stuff around this.
NOTE: AutoComplete feature is only available from .NET 2.0
i have a specific state(business case),i want to check it every period of time,to execute an action..they tell me to write a patch to handle this situation ..
the application i works in is a web application (asp.net)..
i don't know how to write the patch ,, and i don't know if the patch is the ideal solution in this state or not..
please any suggestions ,, any details explanation for this issue..
thanks in advance.
Firstly, it is quite simple to setup a timer to do this check. Initialise a timer,
int _State;
System.Timers.Timer stateCheckTimer = new System.Timers.Timer();
stateCheckTimer.Interval = 1000; // TODO - set to desired interval (in ms)
stateCheckTimer.AutoReset = true;
stateCheckTimer.Elapsed += stateCheckTimer_Elapsed;
Then just check your state in the stateCheckTimer_Elapsed function,
void stateCheckTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Check for the desired state
if (_State == 1)
{
// Do something
}
}
The most difficult thing will be accessing the _State, so you'll probably have to put the timer in the same location as it (or have it passed, whatever works). I would suggest an event driven solution though. Make a public event handler on your class that handles the state,
public EventHandler OnStateChanged;
Then, encapsulate the access to your state variable (in this example, _State) so that you control the setting of it. When it is set, fire off this event. I do this through a property,
public int State
{
get { return _State; }
set
{
_State = value;
if (OnStateChanged != null)
{
OnStateChanged(this, null);
}
}
}
Then, you just need to wire up an event handle to execute your desired action,
OnStateChanged += StateChangeAction;
And in that function execute your desired action,
void StateChangeAction(object sender, EventArgs args)
{
// Check for the desired state
if (_State == 1)
{
// Do something
}
}
(you will have to pass the state in through the EventArgs args but that is pretty simple to do). This way, whenever the state changes you will immediately be able to act upon it (send an email, do whatever it is) rather than having to poll the state every x seconds or minutes. It will use less resources, be more reactive (quicker), and ultimately be neater code! If you are able to do it this way, I would highly recommend it.
this checking is done from the browser or on the server side application ?
if it is done from the client( Browser ) than you can do it with JavaScript See this Post
If you want to do it from the Server Side code than , you can do it with a thread, make thread sleep for some time and when it's wake up than check the state of your object
Is the action to be executed a database one, e.g. update some row in the database? If yes you can create a database job that handles this situation.
What about writing a small simple service that works in the background 24/7. I think its the simplest solution.
I have a web service with two methods:
RetrieveFirstLevelOptions() and RetrieveSecondLevelOptions(int levelOneOption).
The GUI contains two comboBoxes: FirstLevelOptionsCombo and SecondLevelOptionsCombo.
I am having trouble with creating a control flow for the initialization stage when I have to make a request to RetrieveFirstLevelOptions() and then, once the results are in, call RetrieveSecondLevelOptions(default levelOneOption = 0).
The problem is that since everything happens asynchronously I don't know what the best approach is to allow this behaviour take place once and only once, at the beginning.
An option I would love to have is to attach a second event handler to the RetieveFirstLevelOptionsCompleted event and have it remove itself after running only once. But it looks like such a behaviour is impossible to get.
Another option would be to have a boolean flag to indicate whether in Initialization phase and if it is, then the handler for RetrieveFirstLevelOptionsCompleted would execute some additional logic. However this idea makes it look like all event handlers would have to check for state information and do different things depending on the current state. This seems to be bad design because the control flow seems to be descentralized.
I want to have a centralized control flow mechanism that will make the decisions in one spot. But how can this be done when everything is executed asynchronously?
"An option I would love to have is to attach a second event handler to the RetieveFirstLevelOptionsCompleted event and have it remove itself after running only once. But it looks like such a behaviour is impossible to get."
Is there some reason this isn't working:
class Example
{
SomeWebService myService;
Example()
{
// do stuff
myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod;
}
void MyHandlerMethod(object sender, RetrieveFirstLevelOptionsCompletedEventArgs e)
{
// do stuff
myService.RetrieveFirstLevelOptionsCompleted -= MyHandlerMethod;
// potentially attach next event handler for all subsequent calls
myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod2;
}
}
The pattern that I usually use in a situation like this is to create a wrapper around the Async web service proxy method that accepts a callback method. The callback method then gets passed to the RetrieveFirstLevelOptionsAsync() method like so:
public void RetrieveFirstLevelOptions(Action callback)
{
client.RetrieveFirstLevelOptionsAsync(callback);
}
void client_RetrieveFirstLevelOptionsCompleted(object sender, AsyncCompletedEventArgs e)
{
var callback = e.UserState as Action;
if (callback != null)
{
callback();
}
}
So when you call RetrieveFirstLevelOptions(), you just pass the callback that you want to run only once, and you don't ever have to worry about it getting called multiple times. Presumably you'd put your call to RetrieveSecondLevelOptions() within that callback.