I have some async services that I would like to call in different places in Xamarin application. I port my code from native UWP app with Prism.
Some time ago I was able to do this by declaring making methods like
protected override void OnInitialized()
or
public override async void OnNavigatedTo(NavigationParameters parameters)
used await there. However, it stopped working.
Trying to use GetAwaiter().GetResult() blocks execution and results in deadlock.
This is kind of weird, considering that INavigationService.NavigateAsync itself is async method, but samples suggest to use in OnInitialized without any await, which I believe is wrong.
So, does anyone have a suggestion how to proper make async calls in Prism.Forms?
OnNavigatedTo gets called from the UI thread (it is part of the UI Lifecycle). If you block inside that method, you will of course have a deadlock.
Just because NavigateAsync returns a Task and has an async name, doesn't mean everything in that method happens on another thread. It just means it usually does something, that you could wait for.
The problem here is, that OnNavigatedTo is returning void, so it will return to the caller, once you have an await in there. That doesn't stop you from using it, you just cant block there.
public override async void OnNavigatedTo(NavigationParameters parameters)
{
// do sync stuff
await DoSomethingAsync();
// this happens after all the other lifecycle methods
}
Just be aware, that everything after the await just happens after the whole navigation is done. And that exceptions thrown in there will not show up (it's basically fire and forget).
You can always make the continuation explicit by not using async/await and using .ContinueWith(...) instead.
Related
...without async await...
I would like to demonstrate the classic completion handler logic with Task library. (not with the pure Thread object) So I would like to create a Task instance, run it (against the default thread pool, or any way), and have a completion handler, which runs (probably on the Task's thread) on completion and access to the result.
(I do know now we can use async await, also know about marshaling, also know about ASP.NET threads and contexts, please do not explain those.)
I would like to demonstrate the classic completion handler logic with Task library.
I really don't think this is very useful. It sounds like you're describing continuation passing style, which was not widely adopted among .NET libraries. There was one HTTP library using it, but other than that I did not see much adoption of that pattern in .NET at all. On the other hand, JavaScript (particularly server-side JS) did use CPS quite a bit.
That said, if you really want to do it, you can:
public static void Run<T>(Func<T> action, Action<Exception> onError, Action<T> onComplete)
{
Task.Run(action).ContinueWith(
t =>
{
T result;
try
{
result = t.Result;
}
catch (Exception ex)
{
onError(ex);
return;
}
onComplete(result);
},
default,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
In Blazor Web, I have a method called from a button that does an HttpClient call to an API and then populates a field (Result) on the form. When I call it the first time, nothing happens. When I call it the second time, the field gets populated. Chrome confirms that the API call is made successfully both times. It looks like the code after the await doesn't execute until the 2nd call. What am I doing wrong?
private async void DoAPICall()
{
VerificationReturnType ReturnData = await Http.GetFromJsonAsync<VerificationReturnType>(APIMethod);
Result = String.Format("TrustedCookie: {0}\r\nVerificationCookie: {1}\r\nError: {2}\r\n", ReturnData.TrustedCookie, ReturnData.VerificatonCookie, ReturnData.Error);
}
Fixed by changing the return type of the DoAPICall from void to Task. Even though the DoAPICall is functionally the event handler for the web form button onclick event and async event handlers usually have to have the void return type, in this (Blazor Web) context, the method must have the Task return type.
Also, (which was my first solution), don't try to call the GetFromJsonAsync method synchronously by appending .Result, like you might when writing a backend C# application. It will compile OK but blow up running in the browser.
Really hope this helps someone else with beginner mistakes - Blazor Web has such potential!
The question is not how to get it working, it works. I am just interested but can't find out what goes on in the background to make it work.
Prime example is the standard Blazor server webapp template, which has a "counter" and a "fetchdata" component.
In the fetchdata component, there is protected override async Task OnInitializedAsync() that gets called, and the component renders itself. If the OnInitializedAsync() does not return in time, the render still happens, in the example just writing out loading... Then when the OnInitializedAsync() actually finishes, the component is magically re-rendered, but what caused the re-render? how is it wired together?
Does the framework peek at the class' memory every so often to figure out if a rerender is needed? Is it just that there is a call for the page render before the OnInitializedAsync() call and one after awaiting it?
This is all based on async programming...
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
The OnInitializedAsync method you've mentioned has two parts: synchronous and asynchronous. When the OnInitializedAsync method starts executing, a call to the awaitable GetForecastAsync method is made, control is yielded to the calling code, Blazor runtime, that starts rendering the UI without delay. This is the first time your component is rendered. This is also why you must check in code that the forecasts variable is not null. When GetForecastAsync returns and the forecasts variable is populated, more code (if exists) is executed to the end of the method, after which your component re-renders again, this time forecasts is not null, and thus the table is rendered. Of course, this was a simplistic explanation. You can inspect the process, step by step, by viewing the code that does this: It all starts here. It shouldn't be difficult to follow. No magic
Hope this helps...
I'm trying to call an asynchronous method from a synchronous method like below:
1. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But this lead to a deadlock, await is not getting the results from the method - GetWordsByCodeAsync
I've done a bit of research and came to know that if we are calling an async method from synchronous method we should use Task.Run
When I changed the code like below, it worked:
2. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = Task.Run<List<Words>>(async () => await GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But I didn't get the context, why it caused a deadlock for 1st way and 2nd one worked fine.
I'd like to know:
What's the difference between two ways?
Is second one the correct way to call async method from synchronous method?
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
Also, please suggest any best practices to better do it as I have to do 5 async calls from a synchronous method - just like taskWords, I have taskSentences etc.,
Note: I don't want to change everything to async. I want to call async method from synchronous method.
I don't want to change everything to async. I want to call async method from synchronous method.
From a technical standpoint, this doesn't make sense. Asynchronous means it doesn't block the calling thread; synchronous means it does. So you understand that if you block on asynchronous code, then it's no longer truly asynchronous? The only benefit to asynchronous code is that it doesn't block the calling thread, so if you block on the asynchronous code, you're removing all the benefit of asynchrony in the first place.
The only good answer is to go async all the way. There are some rare scenarios where that's not possible, though.
What's the difference between two ways?
The first one executes the asynchronous code directly and then blocks the calling thread, waiting for it to finish. You're running into a deadlock because the asynchronous code is attempting to resume on the calling context (which await does by default), and presumably you're running this code on a UI thread or in an ASP.NET Classic request context, which only allow one thread in the context at a time. There's already a thread in the context (the one blocking, waiting for the task to finish), so the async method cannot resume and actually finish.
The second one executes the asynchronous code on a thread pool thread and then blocks the calling thread, waiting for it to finish. There is no deadlock here because the asynchronous code resumes on its calling context, which is a thread pool context, so it just continues executing on any available thread pool thread.
Is second one the correct way to call async method from synchronous method?
There is no "correct" way to do this. There are a variety of hacks, each of which has different drawbacks, and none of which work in every situation.
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
It will not deadlock. What it does, though, is execute GetWordsAsync on a thread pool thread. As long as GetWordsAsync can be run on a thread pool thread, then it will work.
Also, please suggest any best practices to better do it
I have written an article on the subject. In your case, if GetWordsAsync is safe to call on a thread pool thread, then the "blocking thread pool hack" is acceptable.
Note that this is not the best solution; the best solution is to go async all the way. But the blocking thread pool hack is an acceptable hack if you must call asynchronous code from synchronous code (again, it's "acceptable" only if GetWordsAsync is safe to call on a thread pool thread).
I would recommend using GetAwaiter().GetResult() rather than Result, in order to avoid the AggregateException wrapper on error. Also, the explicit type arguments are unnecessary, and you can elide async/await in this case:
var taskWords = Task.Run(() => GetWordsAsync(code));
return taskWords.GetAwaiter().GetResult();
I have a web site which makes frequent requests to an external web service, and I'd like these calls to be async and parallel to avoid blocking and to speed up the site a bit. Basically, I have 8 widgets, each of which has to make its own web call(s).
For some reason, only the first 3 or so of them truly load async, and then the threads don't free up in time, and the rest of the widgets load sequencially. If i could get 3 of them to load in parallel, then 3 more in parallel, then 2 more in parallel, i'd be happy. So the issue is really that the threads aren't freeing up in time.
I'm guessing the answer has to do with some IIS configuration. I'm testing on a non-server OS, so maybe that's part of it.
Edit for #jon skeet:
I'm using reflection to invoke the web calls like this:
output = methodInfo.Invoke(webservice, parameters);
The widget actions (which eventually call the web service) are called via a jquery $.each() loop and the .load function (maybe this causes a bottleneck?). The widget actions are set up as async methods in an async controller.
Here is the code for one of the async methods (they are all set up like this):
public void MarketTradeWidgetAsync()
{
AsyncManager.OutstandingOperations.Increment();
//a bunch of market trade logic
//this eventually calls the web service
PlanUISetting uiSettingMarketQuotesConfig = WebSettingsProviderManager.Provider.GetMarketQuotes(System.Configuration.ConfigurationManager.AppSettings["Theme"], SessionValues<String>.GlobalPlanID, SessionValues<String>.ParticipantID, "MARKETQUOTES");
AsyncManager.OutstandingOperations.Decrement();
}
public ActionResult MarketTradeWidgetCompleted(MarketTradeTool markettradetool)
{
if (Session.IsNewSession)
return PartialView("../Error/AjaxSessionExpired");
else
{
ViewData["MarketData"] = markettradetool;
return PartialView(markettradetool);
}
}
And, like I said, these methods are called via jquery. My thinking is that since the action methods are async, they should give control back to the jquery after they get called, right?
SessionState = "readonly" for the page at hand fixed this issue. Evidently session locking was the issue.