Blazor and ContinueWith on page load - async-await

I am new to Blazor. I'm working on a Server App (not WASM).
On a page load, I am loading 2 things to a page. Item1 is loaded at the same time as Item2 via API calls. I'd like individual items to show up as soon as they are available. I was thinking something like
protected override async Task OnInitializedAsync()
{
var t1 = _service.GetItem1().ContinueWith(t => {
Item1Loaded = true;
Item2State = t.Result;
await InvokeAsync(StateHasChanged);
});
var t2 = _service.GetItem2().ContinueWith(t => {
Item2Loaded = true;
Item2State = t.Result;
await InvokeAsync(StateHasChanged);
});
}
I have a couple questions about this though:
Do I need to worry about canceling these lines if the user navigates away from the component? (would changing a state variable after the component is removed cause a problem) or does Blazor handle that at the framework level somehow?
Do I need to ensure this gets back to a certain thread with a Synchronization Context? It seems like InvokeAsync just does this for me but want to be sure.
Its hard to find lots of modern examples of ContinueWith. async/await is dominant, but I don't think it allows continuations to execute in the order they complete. Is this a reasonable use of it?

Since you are using Server side you can do this more cleanly (ContinueWith is more or less obsolete since async / await):
protected override async Task OnInitializedAsync()
{
var t1 = Task.Run(async () =>
{ Item1State = await _service.GetItem1();
Item1Loaded = true; // you can probably derive this from Item1State
await InvokeAsync(StateHasChanged);
});
var t2 = Task.Run(async () =>
{ Item2State = await _service.GetItem2();
Item2Loaded = true;
await InvokeAsync(StateHasChanged);
});
await Task.WhenAll(t1, t2);
}
No need to call StateHasChanged() here.
Without the ItemLoaded guards you could do this without Task.Run().

Do I need to worry about canceling these lines if the user navigates away
Most modern DB stuff can be passed a cancellation token. So, use that if you wish to cancel the operation. If It's your own code and the operations are long running, consider using cancellation tokens.
Do I need to ensure this gets back to a certain thread with a Synchronization Context?
Calling await InvokeAsync(StateHasChanged); ensures the UI code is run on the UI thread.
Question 3
Stick with simple await. Yes, it executes in order. And call await InvokeAsync(StateHasChanged) between operations to update the UI if you have more than two await operations.
Note : This will only work if you await real async code, not sync code wrapped in a Task! If there are no yields, the Renderer gets no thread time so the UI doesn't get updated till it gets some.

Related

How to best implement a Promise semaphore?

I use a semaphore for two processes that share a resource (rest api endpoint), that can't be called concurrent. I do:
let tokenSemaphore = null;
class restApi {
async getAccessToken() {
let tokenResolve;
if (tokenSemaphore) {
await tokenSemaphore;
}
tokenSemaphore = new Promise((resolve) => tokenResolve = resolve);
return new Promise(async (resolve, reject) => {
// ...
resolve(accessToken);
tokenResolve();
tokenSemaphore = null;
});
}
}
But this looks too complicated. Is there a simpler way to achieve the same thing?
And how to do it for more concurrent processes.
This is not a server side Semaphore. You need interprocess communication for locking processes which are running independently in different threads. In that case the API must support something like that on the server side and this here is not for you.
As this was the first hit when googling for "JavaScript Promise Semaphore", here is what I came up with:
function Semaphore(max, fn, ...a1)
{
let run = 0;
const waits = [];
function next(x)
{
if (run<max && waits.length)
waits.shift()(++run);
return x;
}
return (...a2) => next(new Promise(ok => waits.push(ok)).then(() => fn(...a1,...a2)).finally(_ => run--).finally(next));
}
Example use (above is (nearly) copied from my code, following was typed in directly and hence is not tested):
// do not execute more than 20 fetches in parallel:
const fetch20 = Semaphore(20, fetch);
async function retry(...a)
{
for (let retries=0;; retries++)
{
if (retries)
await new Promise(ok => setTimeout(ok, 100*retries));
try {
return await fetch20(...a)
} catch (e) {
console.log('retry ${retries}', url, e);
}
}
}
and then
for (let i=0; ++i<10000000; ) retry(`https://example.com/?${i}`);
My Browser handles thousands of asynchronous parallel calls to retry very well. However when using fetch directly, the Tabs crash nearly instantly.
For your usage you probably need something like:
async function access_token_api_call()
{
// assume this takes 10s and must not be called in parallel for setting the Cookie
return fetch('https://api.example.com/nonce').then(r => r.json());
}
const get_access_token = Semaphore(1, access_token_api_call);
// both processes need to use the same(!) Semaphore, of course
async function process(...args)
{
const token = await get_access_token();
// processing args here
return //something;
}
proc1 = process(1);
proc2 = process(2);
Promise.all([proc1, proc2]).then( //etc.
YMMV.
Notes:
This assumes that your two processes are just asynchronous functions of the same single JS script (i.E. running in the same Tab).
A Browser usually does not open more than 5 concurrent connects to a backend and then pipelines excess requests. fetch20 is my workaround for a real-world problem when a JS-Frontend needs to queue, say, 5000 fetches in parallel, which crashes my Browser (for unknown reason). We have 2021 and that should not be any problem, right?
But this looks too complicated.
Not complicated enough, I'm afraid. Currently, if multiple code paths call getAccessToken when the semaphore is taken, they'll all block on the same tokenSemaphore instance, and when the semaphore is released, they'll all be released and resolve roughly at the same time, allowing concurrent access to the API.
In order to write an asynchronous lock (or semaphore), you'll need a collection of futures (tokenResolvers). When one is released, it should only remove and resolve a single future from that collection.
I played around with it a bit in TypeScript a few years ago, but never tested or used the code. My Gist is also C#-ish (using "dispoables" and whatnot); it needs some updating to use more natural JS patterns.

NetworkStream ReadAsync and WriteAsync hang infinitelly when using CancellationTokenSource - Deadlock Caused by Task.Result (or Task.Wait)

After reading pretty much every question on Stack Overflow and Microsoft's documentation about NetworkStream, I dont understand what is wrong with my code.
The problem I see is that my method GetDataAsync() hangs very often. I call this method from Init Method like so:
public MyView(string id)
{
InitializeComponent();
MyViewModel myViewModel = session.Resolve<MyViewModel>(); //Autofac
myiewModel.Init(id);
BindingContext = myViewModel;
}
Above, my View does its initialization, then resolves MyViewModel from Autofac DiC and then calls MyViewModel Init() method to do some additional setup on the VM.
The Init method then calls my Async method GetDataAsync which return a IList like so:
public void Init()
{
// call this Async method to populate a ListView
foreach (var model in GetDataAsync("111").Result)
{
// The List<MyModel> returned by the GetDataAsync is then
// used to load ListView's ObservableCollection<MyModel>
// This ObservableCollection is data-bound to a ListView in
// this View. So, the ListView shows its data once the View
// displays.
}
}
, and here is my GetDataAsync() method including my comments:
public override async Task<IList<MyModel>> GetDataAsync(string id)
{
var timeout = TimeSpan.FromSeconds(20);
try
{
byte[] messageBytes = GetMessageBytes(Id);
using (var cts = new CancellationTokenSource(timeout))
using (TcpClient client = new TcpClient(Ip, Port))
using (NetworkStream stream = client.GetStream())
{
await stream.WriteAsync(messageBytes, 0, messageBytes.Length, cts.Token);
await stream.FlushAsync(cts.Token);
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
int bytesRead = 0;
await Task.Delay(500);
while (stream.DataAvailable) // need to Delay to wait for data to be available
{
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cts.Token);
builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
}
string msg = buffer.ToString();
}
return ParseMessageIntoList(msg); // parses message into IList<MyModel>
}
catch (OperationCanceledException oce)
{
return await Task.FromResult<IList<RoomGuestModel>>(new List<RoomGuestModel>());
}
catch (Exception ex)
{
return await Task.FromResult<IList<RoomGuestModel>>(new List<RoomGuestModel>());
}
}
I would expect that a ReadAsync or WriteAsync either complete successfully, throw some exception, or get cancelled after 10 seconds in which case I would catch OperationCanceledException.
However, it just hangs endlessly when I call method above. If I am debugging and have some breakpoints in the code above, I will be able to go through the method entirely but if I call it 2nd time, app just hangs forever.
I am new to Tasks and Async programming, so I am also not sure I do my cancellations and exception handling properly here?
UPDATE AND FIX
I figured out how to fix the deadlock issue. In hope this will help others sho might run into the same issue, I'll first explain it. The articles that helped me a lot are:
https://devblogs.microsoft.com/pfxteam/await-and-ui-and-deadlocks-oh-my/ by Stephen Taub
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/ by James Montemagno
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx by StephenCleary
https://blog.xamarin.com/getting-started-with-async-await/ by Jon Goldberger
#StephenCleary was great help understanding the issue. Calling Result or Wait (above, I call Result when calling GetDataAsync) will lead to dead-lock.
The context thread (UI in this case) is now waiting for GetDataAsync to complete, but GetDataAsync captures the current context-thread (UI thread), so it can resume on it once it gets data from TCP. But since this context-thread is now blocked by call to Result, it cannot resume.
The end result is that it looks like call to GetDataAsync has deadlocked but in reality, it is call to Result that deadlocked.
After reading tons of articles from #StephenTaub, #StephenCleary, #JamesMontemagno, #JoeGoldenberger (thank you all), I started getting understanding of the issue (I am new to TAP/async/await).
Then I discovered continuations in Tasks and how to use them to resolve the issue (thanks to Stephen Taub's article above).
So, instead of calling it like:
IList<MyModel> models = GetDataAsync("111").Result;
foeach(var model in models)
{
MyModelsObservableCollection.Add(model);
}
, I call it with continuation like this:
GetDataAsync(id)
.ContinueWith((antecedant) =>
{
foreach(var model in antecedant.Result)
{
MyModelsObservableCollection.Add(model);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((antecedant) =>
{
var error = antecedant.Exception.Flatten();
}, TaskContinuationOptions.OnlyOnFaulted);
This seam to have fixed my deadlocking issue and now my list will load fine even though it is loaded from the constructor.
So, this seam to work just fine. But #JoeGoldenberger also suggests another solution in his article https://blog.xamarin.com/getting-started-with-async-await/ which is to use Task.Run(async()=>{...}); and inside that await GetDataAsync and load ObservableCollection. So, I gave that a try as well and that is not blocking either, so working great:
Task.Run(async() =>
{
IList<MyModel> models = await GetDataAsync(id);
foreach (var model in models)
{
MyModelsObservableCollection.Add(model);
}
});
So, it looks like either of these 2 will remove deadlock just fine. And since above my Init method is called from a c-tor; therefore, I cannot make it Async and await on this, using one of the 2 methods described above resolves my problem. I dont know which one is better but in my tests, they do work.
Your problem is most likely due to GetDataAsync("111").Result. You shouldn't block on async code.
This can cause deadocks. E.g., if you're on a UI thread, the UI thread will start GetDataAsync and run it until it hits an await. At this point, GetDataAsync returns an incomplete task, and the .Result call blocks the UI thread until that task is completed.
Eventually, the inner async call completes and GetDataAsync is ready to resume executing after its await. By default, await captures its context and resumes on that context. Which in this example is the UI thread. Which is blocked since it called Result. So, the UI thread is waiting for GetDataAsync to complete, and GetDataAsync is waiting for the UI thread so it can complete: deadlock.
The proper solution is to go async all the way; replace .Result with await, and make the necessary changes to other code for that to happen.
As stated in my update, going async all the way by providing an async lambda like below resolved the issue for me
Task.Run(async() =>
{
IList<MyModel> models = await GetDataAsync(id);
foreach (var model in models)
{
MyModelsObservableCollection.Add(model);
}
});
Loading asynchronously an observable collection in a ctor this way (in my case, ctor calls Init which then uses this Task.Run) solves problem

await async code seems to still be running sync

I'm new to async / await, and have been trying to implement it in my 4.6 web api 2 project.
public class MyController : ApiController
{
public async Task<Thing> Search(String searchTerms)
{
myThing = new Thing();
myThing.FirstProperty = await doFirstPropertyAsync(searchTerms);
myThing.SecondProperty = await doSecondPropertyAsync(searchTerms);
return myThing;
}
}
Basically I'm returning a class (Thing) that has two properties that take a few seconds each to populate. I'm actually loading maybe ~10 properties, but it's the same logic for all of them.
public async Task<MyCoolSubObject> doFirstPropertyAsync(string searchTerms)
{
SomeController sController = new SomeController();
Debug.WriteLine("first - starting.");
var x = await Task.Run(()=>sController.Lookup(searchTerms));
Debug.WriteLine("first - finishing.");
return x;
}
public async Task<MyCoolSubObject> doSecondPropertyAsync(string searchTerms)
{
SomeOtherController sController = new SomeOtherController();
Debug.WriteLine("second - starting.");
var x = await Task.Run(()=>sController.Lookup(searchTerms));
Debug.WriteLine("second - finishing.");
return x;
}
What's got my scratching my head:
When I look at the debug outputs, the first property assignment method call starts and finishes before the second completes. Again, I actually have like ten of these and no matter what order I put the property assignments in they complete in a serial fashion (ie: nothing starts until another one finishes).
These property assignments under the hood are basically doing database calls that take a while, hence I wanted them running in parallel if possible. The methods themselves ( SomeController.Lookup(string) ) contain no await/async/task stuff.
Again, I actually have like ten of these and no matter what order I
put the property assignments in they complete in a serial fashion (ie:
nothing starts until another one finishes).
This happens because in your code you use the await keyword as soon as you kickoff the task, by doing that you prevent the method to continue to execute the next statement before the task will be done.
If you want to run your tasks in parallel you should kickoff all of them and only then await all of them using Task.WhenAll:
public async Task<Thing> Search(String searchTerms)
{
myThing = new Thing();
var firstTask = doFirstPropertyAsync(searchTerms);
var secondTask = doSecondPropertyAsync(searchTerms);
await Task.WhenAll(firstTask, secondTask);
myThing.FirstProperty = await firstTask;
myThing.SecondProperty = await secondTask;
return myThing;
}
Note that when we await every task separately after we await Task.WhenAll the tasks have already been done, we do that in order to get the result from the task, although we can use the Result property (it will not block since we know the task has already been done) I prefer to use await for consistency reasons.

Time-based cache for REST client using RxJs 5 in Angular2

I'm new to ReactiveX/RxJs and I'm wondering if my use-case is feasible smoothly with RxJs, preferably with a combination of built-in operators. Here's what I want to achieve:
I have an Angular2 application that communicates with a REST API. Different parts of the application need to access the same information at different times. To avoid hammering the servers by firing the same request over and over, I'd like to add client-side caching. The caching should happen in a service layer, where the network calls are actually made. This service layer then just hands out Observables. The caching must be transparent to the rest of the application: it should only be aware of Observables, not the caching.
So initially, a particular piece of information from the REST API should be retrieved only once per, let's say, 60 seconds, even if there's a dozen components requesting this information from the service within those 60 seconds. Each subscriber must be given the (single) last value from the Observable upon subscription.
Currently, I managed to achieve exactly that with an approach like this:
public getInformation(): Observable<Information> {
if (!this.information) {
this.information = this.restService.get('/information/')
.cache(1, 60000);
}
return this.information;
}
In this example, restService.get(...) performs the actual network call and returns an Observable, much like Angular's http Service.
The problem with this approach is refreshing the cache: While it makes sure the network call is executed exactly once, and that the cached value will no longer be pushed to new subscribers after 60 seconds, it doesn't re-execute the initial request after the cache expires. So subscriptions that occur after the 60sec cache will not be given any value from the Observable.
Would it be possible to re-execute the initial request if a new subscription happens after the cache timed out, and to re-cache the new value for 60sec again?
As a bonus: it would be even cooler if existing subscriptions (e.g. those who initiated the first network call) would get the refreshed value whose fetching had been initiated by the newer subscription, so that once the information is refreshed, it is immediately passed through the whole Observable-aware application.
I figured out a solution to achieve exactly what I was looking for. It might go against ReactiveX nomenclature and best practices, but technically, it does exactly what I want it to. That being said, if someone still finds a way to achieve the same with just built-in operators, I'll be happy to accept a better answer.
So basically since I need a way to re-trigger the network call upon subscription (no polling, no timer), I looked at how the ReplaySubject is implemented and even used it as my base class. I then created a callback-based class RefreshingReplaySubject (naming improvements welcome!). Here it is:
export class RefreshingReplaySubject<T> extends ReplaySubject<T> {
private providerCallback: () => Observable<T>;
private lastProviderTrigger: number;
private windowTime;
constructor(providerCallback: () => Observable<T>, windowTime?: number) {
// Cache exactly 1 item forever in the ReplaySubject
super(1);
this.windowTime = windowTime || 60000;
this.lastProviderTrigger = 0;
this.providerCallback = providerCallback;
}
protected _subscribe(subscriber: Subscriber<T>): Subscription {
// Hook into the subscribe method to trigger refreshing
this._triggerProviderIfRequired();
return super._subscribe(subscriber);
}
protected _triggerProviderIfRequired() {
let now = this._getNow();
if ((now - this.lastProviderTrigger) > this.windowTime) {
// Data considered stale, provider triggering required...
this.lastProviderTrigger = now;
this.providerCallback().first().subscribe((t: T) => this.next(t));
}
}
}
And here is the resulting usage:
public getInformation(): Observable<Information> {
if (!this.information) {
this.information = new RefreshingReplaySubject(
() => this.restService.get('/information/'),
60000
);
}
return this.information;
}
To implement this, you will need to create your own observable with custom logic on subscribtion:
function createTimedCache(doRequest, expireTime) {
let lastCallTime = 0;
let lastResult = null;
const result$ = new Rx.Subject();
return Rx.Observable.create(observer => {
const time = Date.now();
if (time - lastCallTime < expireTime) {
return (lastResult
// when result already received
? result$.startWith(lastResult)
// still waiting for result
: result$
).subscribe(observer);
}
const disposable = result$.subscribe(observer);
lastCallTime = time;
lastResult = null;
doRequest()
.do(result => {
lastResult = result;
})
.subscribe(v => result$.next(v), e => result$.error(e));
return disposable;
});
}
and resulting usage would be following:
this.information = createTimedCache(
() => this.restService.get('/information/'),
60000
);
usage example: https://jsbin.com/hutikesoqa/edit?js,console

Handling configuration change for async methods

I have an activity which has an async method in it. This async method is long running. After the async method returns, the UI needs to be updated and some of the controls reference the activity.
At the moment, everything works correctly if you do not have a configuration change (like screen rotation) while the async task is running. However, if a configuration change happens while it is running, then the exception Activity is destroyed is thrown and the UI is not updated. From what reading I have done, this seems to be because the async method captures context and then tries to update the old context which is of course destroyed after the configuration change.
My question is: What are the best ways to solve this problem or at worst case scenario work around it?
I personally think you have only three options
You can disable rotation permanently or temporary, but this is a bad practice
To disable it permanently set ConfigurationChanges
[Activity(Label = "...", ConfigurationChanges = Android.Content.PM.ConfigChanges.KeyboardHidden | Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
To disable it temporary while task working you should disable rotation handling,
disable
this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Nosensor;
enable
this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Sensor;
If you are using fragment you can prevent fragment destroy with RetainInstance = true. That might work, but i never tested it.
You can cancel task with CancelationToken and restart it in OnRestoreInstanceState()
Here is example how to cancel task
{
CancellationTokenSource cts;
...
// If a download process is already underway, cancel it.
if (cts != null)
{
cts.Cancel();
}
// Now set cts to cancel the current process if the button is chosen again.
CancellationTokenSource newCTS = new CancellationTokenSource();
cts = newCTS;
try
{
//Send cts.Token to carry the message if there is a cancellation request.
await AccessTheWebAsync(cts.Token);
}
// Catch cancellations separately.
catch (OperationCanceledException)
{
ResultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
// When the process is complete, signal that another process can proceed.
if (cts == newCTS)
cts = null;
}
And in the task
async Task AccessTheWebAsync(CancellationToken ct)
{
...
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// Check for cancellations before displaying information about the
// latest site.
ct.ThrowIfCancellationRequested();
...
}
There are plenty of things you could do, but please don't go and disable the phones ability to turn the screen -- that is just going to ignore your users.
At a highlevel you will have to do two things:
Make sure the async task keeps running and is not restarted if the activity dies.
You can solve that by moving the task either into the application class or (cleaner) into a headless fragment with setRetainInstance set to true.
In the onDestroy method in the activity, remove it from the async task, in the onCreate task give the activity to the async task (if it exist).
This is what prevents the async task from calling the old context and can be done with a simple java setter on the async task. Don't forget to cache the result in the task if the activity is currently not connected.
In the end what I ended up doing was encapsulating the async task in another class which held a reference to the current activity, which implemented and interface which defined a method which handles the async response and updates the UI.
The activity held a static variable of the encapsulated async task, and if it was running during a config change, the encapsulated async's task reference to the activity was updated to the new activity.

Resources