I developed an asp.net solution for a customer some months ago, in which we're using AzureSearch in an input box. My approach was to send an ajax request once a second had transcurred since the last keystroke from the user. But our customer wanted it to always happen onchange of the input box, so we did that.
It has resulted in the client reporting a bug - inconsistent searches. It's because of a race condition, I logged the async calls and that's what happened. I'm thinking about adding a 0.5 sec delay to the javascript autocomplete. Or is there a better way? Like having a pool in javascript. The control we are using is jquery easy autocomplete.
What you're doing is called a "debounce". A debounce is when you have a timer start counting down when a user starts input. If they enter more input before the timer has finished, the timer is reset and starts counting down again. Only when the timer finishes does the AJAX call get made. In this case, a 200ms delay is what research has shown most people consider to still feel responsive.
However, if you really want results to pour in as the user is typing, what you need instead is called a "throttle". A throttle is similar to a debounce, except that it triggers at regular intervals, rather than waiting for the input to stop. To build one you'd still have a timer, however, you wouldn't reset it each time the user enters more input. Instead, you'd use a boolean to track whether or not new input had been entered. When the timer finishes, it checks if the boolean is true, if it is, set it to false and restart the timer counting down.
You could improve either method by keeping track of whether an AJAX call was already taking place. In both cases, if the timer runs out and the boolean tracking if a call is in progress is true, restart the timer.
Both a debounce and throttle are already available in several utility libraries such as lodash. You can use them to to wrap your existing event handlers.
var myInputChangeHandler = function() {
// do ajax call
};
// throttled handler will only be called every 200 ms...
var throttled = _.throttle(myInputChangeHandler, 200);
// ...no matter how many times this event fires
jQuery('input[type=text]').on('change', throttled);
In the end I did not need to add a delay or a throttle. By checking its official site, I discovered two very useful properties in jquery-easy-autocomplete, which are:
matchResponseProperty: To avoid race conditions, since the last ajax call musn't neccessarily be the last response from the backend service, it will take the last response which has a property named as specified with this attribute, which matches with the current text in the input.
listLocation: I was trying to render a json with an anonymous list of items and a property called InputPhrase, until I came to this, so I specified the list location in the base response object and used this model for the response.
public class SearchViewModel
{
public List<dynamic> Items { get; set; }
public string InputPhrase { get; set; }
}
Lastly, I set matchResponseProperty to "InputPhrase", and listLocation to "Items"
Related
How do I setup an event loop (main loop) in a UWP app?
My goal is to have an app that has a main page with a continuously updating calculation, that then continuously updates an image on the page. While that is constantly happening, the user can click a button to change the calculation behavior, or to go to a second page and edit related data.
The user can then click back to the main page and see the image and calculation restart and continuously update. (The calculation is complex, so it should go as fast as possible and use up as much app time as possible).
If there is a way to accomplish this without an event loop I would like to know that also, but so far I have not found a way.
With an event loop, I can simply update the calculation and UI every time through the loop. But I have not found any way to do so. This question asked nearly the same thing, but was never directly answered and had a different use case anyway.
The closest I have found to a solution is to grab the CoreDispatcher from the CoreWindow and use the RunIdleAsync() method to create a loop:
public MainPage()
{
this.InitializeComponent();
Windows.UI.Core.CoreWindow appwindow = Windows.UI.Core.CoreWindow.GetForCurrentThread();
Windows.UI.Core.CoreDispatcher appdispatcher = appwindow.Dispatcher;
//create a continuously running idle task (the app loop)
appdispatcher.RunIdleAsync( (dummyt) =>
{
//do the event loop here
.
.
.
if (appdispatcher.ShouldYield()) //necessary to prevent blocking UI
{
appdispatcher.ProcessEvents(Windows.UI.Core.CoreProcessEventsOption.ProcessAllIfPresent);
}
});
}
The main problem with this is that you can't switch between pages (you get a system exception from dispatching events within an already dispatched event).
Second, this is very messy and requires maintaining extra state in the event loop. Besides, why should I have to go through these contortions just to have some calculations happening while the app is waiting for user input?
Is there a way to do this (besides switching to a C++ DirectX app)?
I don't know about setting up your own event loop, but there is no reason to do so.
What you are talking about sounds like a great case for Tasks. You would start a calculation Task whenever your user did something, having it report its progress via standard C# events if you need mid-operation updates. Those updates would modify properties in your view model which the binding system would then pick up.
You could also make your calculation code cancellable so changes can abort a previous calculation.
All of this involves pretty standard UWP concepts; no need for a special event loop. That you are even considering that makes me think you need to study MVVM and multi-threading/tasks; you are still thinking in a very "Win-Forms" kind of way.
If we're talking about some event loop, or stream, .Net has a great library named Rx, or Reactive Extensions, which may be helpful for you. You can set up a simple flow, something like this:
var source = Observable
// fire event every second
.Interval(TimeSpan.FromSeconds(1), Scheduler.DispatcherScheduler)
// add timestamp for event
.Timestamp()
// gather system information to calculate
.Select(GetSystemInfo);
Note that the events right now are on UI thread, as you need to access the controls. Now you have two options: use Rx for background processing too or use TPL Dataflow' TransformBlock for processing your system information into new image (it can be Observer and Observable at a time). After that you need to get back to UI thread.
First option:
var source = Observable
// fire event every second
.Interval(TimeSpan.FromSeconds(1), DispatcherScheduler.Current)
// add timestamp for event
.Timestamp()
// gather system information to calculate
.Select(GetSystemInfo)
// expensive calculations are done in background
.Select(x => x.ObserveOn(DefaultScheduler.Instance))
.Select(x => Expensive(x))
.Select(x => x.ObserveOn(DispatcherScheduler.Current))
.Select(x => UpdateUI(x));
You probably should split this chain into several observers and observables, still the idea is the same, more information here: Rx Design Guidelines.
Second option:
var action = new TransformBlock<SystemInfo, ImageDelta>(CalculateDelta,
new ExecutionDataflowBlockOptions
{
// we can start as many item processing as processor count
MaxDegreeOfParallelism = Environment.ProcessorCount,
});
IDisposable subscription = source.Subscribe(action.AsObserver());
var uiObserver = action.AsObservable()
.Select(x => x.ObserveOn(DispatcherScheduler.Current))
.Select(x => UpdateUI(x));
I want to note that UWP and MVVM pattern do provide a possibility to work with binding between UI and ObservableCollection, which will help you to notify user in most natural way.
I have the following controller:
[HttpPost]
public ActionResult SomeMethod(string foo, obj bar)
{
//Some Logic
}
Now suppose that from the view that Action is called from a Button or from Ajax (with some edits), and I don't want to receive a double request.
What is the best approach to handle it from server side?
Update
You'd first have to define the time interval that would meet the
criteria of a double request – Jonesopolis
Let's suppose that in this case a double request are when the difference of time between first and 2nd call is less than 1s
Frankly, you can't, at least not totally. There's certain things you can do server-side, but none are fool-proof. The general idea is that you need to identity the POST is some way. The most common approach is to set a hidden input with a GUID or similar. Then, when a request comes in you record that GUID somewhere. This could be in the session, in a database, etc. Then, before processing the request, you check whatever datastore you're using for that GUID. If it exists, it's a duplicate POST, and if not, you can go ahead.
However, the big stipulation here is that you have to record that somewhere, and do that takes some period of time. It might only be milliseconds, but that could be enough time for a duplicate request to come in, especially if the user is double-clicking a submit button, which is most often the cause of a double-submit.
A web server just reponds to requests as they come in, and importantly, it has multiple threads and perhaps even multiple processes serving requests simultaneously. HTTP is a stateless protocol, so the server doesn't care whether the client has made the same request before, because it effectively doesn't know the client has made the same request before. If two duplicate requests are being served virtually simultaneously on two different threads, then it's a race to see if one can set something identifying the other as a duplicate before the other one checks to see if it's a duplicate. In other words, most of the time, you're just going to be out of luck and both requests will go through no matter what you try to do server-side to stop duplicates.
The only reliable way to prevent double submits is to disable the submit button on submit using JavaScript. Then, the user can effectively only click once, even if they double-click. That still doesn't help you if the user disables JavaScript, of course, but that's becoming more and more rare.
Look. Becareful with this approach. You will add most complexity to control this in server side.
First, you need recognize when the multiple requests are comming from the same user.
I don't think that to control this in server side is the best way.
However, if you really want that... look: https://stackoverflow.com/a/218919/2892830
In this link was suggested maintain a list of token. But, in your case, just check if the same token was received more than one time.
You need at least to implement double click on event listener.
UseSubmitBehiviar="false"
OnClientClick="this.disable='true'; this.value="Please wait";"
Check ASP.NET Life cycle
Check Request/Redirect
Add test code to see who is responsible
if (IsPostBack)
{
_CtrlName = thisPage.Request.Params.Get("__EVENTTARGET");
if (_CtrlName != null && _CtrlName == myButton.ID)
{
//Do your thing
}
}
Check IsPostBack in page load and use it correct to prevent dublicate requests.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
How to Cancel/Regulate event which is executing in parallel with same event in another thread.
For e.g. In a textbox, every time we enter a character the event fires if text changed event is defined. But after entering first character, the event (Let us call First Event) takes lot of time (as there will be more strings which match a single character), and does some action like changing content of a title label. And after entering a second character the new event which raised to run in parallel takes less time. So now, the second event which fired after entering second character executes fast and returns first and first event executes last and thus, first event's result will be printed ultimately on the label rather than the second one.
Is there a better way to cancel the first event before starting the second event. One thing that comes to my mind is to register threads on a global list variable and kill all threads which are not dead before starting your execution. Will this work?? Any better way to handle this situation.
P.S. I know that search could be initiated after a space or enter to solve this particular issue. But I think you have already noticed my main point. :)
My favourite library for dealing with this exact problem is Rx.Net with TPL. This behaviour can be easily implemented with a combination of a Cancellable Task with an event observer using Observable.FromAsync
Some code!
var textChanged = Observable.FromEventPattern(x => textBox.TextChanged += x, x => textBox.TextChanged -= x)
.Select(_ => textBox.Text);
IDisposable eventHandler = textChanged.Throttle(TimeSpan.FromMilliseconds(500))
.Select(text => Observable.FromAsync((TaskCancelationToken cancel) => DoSearchTaskAsync(text, cancel)))
.Switch()
.Subscrible(results =>
{
//Update the UI
});
Note there is no need to explicitly type any of this...I am only doing it for clarity, but I am more than likely to have mistyped a class name or two...
EDIT
The Search method would be the method body of Task<TReturn> DoSearchTaskAsync(string, TaskCancellationToken).
The magic sauce comes from the Observable.FromAsync and Observable.Switch.
Each time we have a change in the textBox.Text we fire an event. That is filtered by the .Throttle (as you would expect). The clever bit is when we then create a new event source on DoSearchTaskAsync using Observable.FromAsync. At this point we have an IObservable<IObservable<TResult>>, or another way to put it, an eventsource of an eventsource. The switch means we only want the results from the most recently sent eventsource from the outter eventsource, and kill (Dispose) the subscription of previous eventsources.
The act of disposing the previous Observable.FromAsync will cause the TaskCancellationToken to cancel, and prevent its results bubbling up, whilst we subscribe to the new Task.
All very clever stuff, and I only recently came across this AWESOME pattern (I would credit the author if I could).
As for the Observable.FromEventPattern that is pretty unfortunate, as of C#5, there are no first class eventhandlers, so we pass in a lambda for subscription and a lambda for de-subscription.
The .NET Task API has the concept of cancellation built in. See this page for an example and links to more information. http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
I have a C# .NET 3.5 app that prompts for a username and a PIN. I'd like the app to automatically reset if no PIN is entered for x seconds. If a key is pressed within x seconds, then the timer should reset to 0 and start again. I've searched around and found various methods for doing this, using a timer, thread.wait, but I haven't found something that was an example of what I'm trying to accomplish. I think the solution will involve using multiple threads, but I've never had to do this before so I'm not sure where to start on this.
Doesn't need to be that clever this, unless it's a behaviour you are going to reuse a lot.
Assuming you are showing this form modally
Put a timer on your form (disabled)
enable when the form is shown.
Add keydown/keypress eventhandlers to the boxes that could have focus
In them restart the timer
If the timer event fires close the form returning a suitable DialogResult Cancel should do it.
Seeing as you reset on keypress, little point in having another thread. If you weren't resetting then M Patel's answer is the way to go, unless you want to reinvent a lot of wheels
You could use the example here which uses the IAsyncResult interface and Action to do it. I myself have used it and it works like a charm. To simplify things just use it as in the example below
Action wrappedAction = () =>
{
// show your input
};
IAsyncResult result = wrappedAction.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
{
/// the user supplied an input and closed the form
wrappedAction.EndInvoke(result);
}
else
{
// the code has timed out so close your input and throw error
}
I have a checkbox list that each time the user selects one item, my ViewModel will ask my service to send the data related to that option.
_myService.GetAssetSpotDataCompleted += GetAssetSpotDataCompleted;
_myService.GetAssetSpotDataAsync(descItem);
Each selected item will call the same service Method and Debugging the service it sends back the right data.
My problem appears when the user checks some of the items while the data is not still received in my ViewModel. Example: the user selects item 1 and item 2, but my viewModel still has no answer from the service.
When my ViewModel receives the information comes the problem, I always receive twice the same data in my e.Result.
That means that it enters to the method GetAssetSpotDataAsync twice but always with the same result instead of the result for the item 1 and then for the item 2.
I have debugged everything and I have focused the problem in these first two lines of the method GetAssetSpotDataCompleted:
((MyServiceClient)sender).GetAssetSpotDataCompleted -= GetAssetSpotDataCompleted;
if (e.Result != null)
Anyone can help me with this?
What is happening is that by the time the response to first request has arrived the service finds 2 delegates listening on GetAssetSpotDataCompleted (one was added when the request was made the other when the second still outstanding request was made).
It will call both the delegates, it has no way to know that the second delegate was only meant for the second outstanding request. When the first is called its code removes one of the delegates from the event. When the second is called then it also removes the remaining delegate leaving the GetAssetSpotDataCompleted as null.
Now when the second request finally completes the service finds GetAssetSpotDataCompleted event is null and does nothing.
One solution would be to only add the event handler once, perhaps at the same point that _myService gets assigned in the ViewModel.
However there may be another issue, there is no guarantee that the responses to the two outstanding requests will arrive in the same order they were sent (although it highly likely that they will.) It may be better then to add an IsBusy boolean property to the ViewModel and set this true when an outstanding request is made, clearing it when completed. Bind this property to a BusyIndicator control (found in the Toolkit). This will prevent user interaction whilst an async operation that will ultimate change the state of the UI is in progress.