i have a Problem in MonoAndroid calling a WCF Service async.
I followed this Tutorial and created the Portable Class Lib. http://nullskull.com/a/10476775/xamarin-cross-platform-application-consuming-wcf--part-1.aspx
Here is my Service Method which is calling the WCF Service:
public async static Task<KeyExchangeModel> GetPublicKeyFromServer(KeyExchangeModel model)
{
try
{
ISyncService client;
client = new SyncServiceClient(_binding, _endpointAddress);
var res = Task<KeyExchangeModel>.Factory.FromAsync(client.BeginGetServerPublicKey, client.EndGetServerPublicKey,
model, null);
await res;
return res.Result;
}
catch (Exception e)
{
return null;
}
}
An here i call the Method and wait till it´s executed.
Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
task.Wait();
KeyExchangeModel serverModel = task.Result;
The Problem is that on Android i never get the Result. It stuck´s in a Loop. No Exception is logged in the Device Log or is thrown.
This code Perfectly works on a Windows Unit Test and on a Windows Phone Project.
I hope anyone can help me.
Thanks a lot.
Your problem is this line here: task.Wait(); Blocking on asynchronous code can cause deadlocks.
By default, await will capture the current "context", and use that context to resume the async method. In this case, it's probably capturing the UI context, which is tied to the UI thread. So, GetPublicKeyFromServer will start the WCF call, capture the UI context, and return an incomplete task. The calling code then calls Task.Wait on that task, which blocks the UI thread until that async method completes.
Later, the WCF call returns, and GetPublicKeyFromServer attempts to resume in the same context (on the UI thread). However, the UI thread is blocked waiting for GetPublicKeyFromServer to complete. This is a classic deadlock situation.
The reason it work in a unit test is because the async method captures a thread pool context instead of the UI context, so it is able to block one thread pool thread in the Wait and another thread pool thread can complete the async method. Normally, a Windows Phone app would have the same problem with UI context as the Android app, so I suspect that there's something different with the test code, and that's why it's not deadlocking on WP.
I describe this problem in more detail on my blog, in an MSDN article, and in my book.
The best resolution for this problem is to use await instead of Task.Wait or Task<T>.Result. I.e., your calling code should be:
Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
KeyExchangeModel serverModel = await task;
This will require your calling code to be async, which in turn requires its callers to be async, etc. This "growth" of async through the codebase is natural and normal.
Related
I have the following in my REST API server(using OWIN):
[ResponseType(typeof(Session))]
[Route("api/v1/async")]
public Session async_status()
{
AsyncStatus();
return new Session() {...};
}
private async Task<int> AsyncStatus()
{
await SyncMethod();
return 42;
}
private Task<int> SyncMethod()
{
CopyFileThatTakesALongTime(....);
// OR
Thread.Sleep(60000);
return Task.FromResult(42);
}
Why dies it block and the client does not get the desired asynchronous-ness. I I would expect that when calling:
await SyncMethod();
The caller would be freed and unblocked while the rest of the sleep would be executed. What am i missing?
P.S: I can easily fix it by replacing this:
AsyncStatus();
With:
Task.Run(() => AsyncStatus() );
The reason i am not doing that is because of this reading:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html
In other words if it's bad to use Task.Run() in a web server as in the above article but you can't use async/await, what is the solution?
An async method only becomes asynchronous when asynchronous work starts.
That is, all of your code will run synchronously until something truly asynchronous starts. Once some truly asynchronous work starts, a Task is returned up the call stack, which then can be awaited (or not) by the calling methods.
The implication of this is that an async method could still hold up the request if you're doing a lot of synchronous work before the asynchronous work. Your example shows that perfectly. Let's break down exactly what a thread is doing:
Start running async_status()
Jump to AsyncStatus()
At await SyncMethod() the thread jumps to SyncMethod().
The thread halts at Thread.Sleep(60000) for 60 seconds.
SyncMethod() returns a complete Task.
Because there is nothing to await, AsyncStatus() continues synchronously and returns a value.
async_status() returns and thus the request.
Thread.Sleep(60000) can be replaced with any processor-intensive task (or any long-running non-async task) and the result would be the same if it happens before the first await in that method.
This is also described in Microsoft's documentation under the heading What happens in an async method. Notice point 3:
Something happens in GetStringAsync that suspends its progress. Perhaps it must wait for a website to download or some other blocking activity. To avoid blocking resources, GetStringAsync yields control to its caller, AccessTheWebAsync.
Control only returns to the calling method when a Task is returned, which only happens when an asynchronous task is actually started. In your example, there isn't any asynchronous task happening. If you added one (even just await Task.Delay(1)) you would see different results. For example, this will return right away:
[ResponseType(typeof(Session))]
[Route("api/v1/async")]
public Session async_status()
{
AsyncStatus();
return new Session() {...};
}
private async Task<int> AsyncStatus()
{
await SyncMethod();
return 42;
}
private async Task<int> SyncMethod()
{
await Task.Delay(1);
Thread.Sleep(60000);
return 42;
}
At await Task.Delay(1) (or any truly asynchronous work):
SyncMethod() returns an incomplete Task to AsyncStatus()
AsyncStatus() returns an incomplete Task to async_status().
That Task is not awaited, so execution of async_status() continues
To answer your question:
You asked:
if it's bad to use Task.Run() in a web server as in the above article but you can't use async/await, what is the solution?
You mentioned the Task.Run Etiquette article. Read his conclusion at the end:
Do not use it just to “provide something awaitable for my async method to use”.
Your purpose here is not to just "provide something awaitable", but to start a background job and not make the client wait until it's done. That's different.
So yes, you could actually use Task.Run(). However, as noted in Stephen Cleary's Fire and Forget on ASP.NET article, the problem with doing it this way is that ASP.NET does not keep track of that background task. So if it's long-running, then recycling the app pool could immediately kill that work. His article describes better methods of performing background work that you don't want to hold up the return of the request.
I'm writing some basic Firebase code in a Xamarin iOS app and am running into a classic deadlock situation with a TaskCompletionSource.
public Task<string> GetUsers()
{
var tcs = new TaskCompletionSource<string>();
_instance.GetChild("users").ObserveSingleEvent(DataEventType.Value,
x => { tcs.SetResult(x); });
return tcs.Task;
}
When I block on this code like so:
var users = GetUsers().Result;
The application deadlocks.
If I understand correctly, the callback is trying to run on the same context that the .Result is waiting on.
What I don't understand is that if I modify my code to await the GetUsers() call in a Task like so:
var result = Task.Run(
async () => await AppContext.Database.GetUsers().ConfigureAwait(false)
).Result;
It still deadlocks.
What's going on here in the second case? Shouldn't the fact that the code is running on another thread due to the Task.Run mean that the outside .Result doesn't block the callback invocation?
EDIT:
Following up on Nkosi's comment I'm asking this because I'm curious as to why the code is blocking. If I await the call
var users = await GetUsers().ConfigureAwait(false);
then the deadlock goes away. I'd just like to understand why it blocks when wrapped in a Task because based on my (clearly incorrect) understanding of Task.Run, it shouldn't.
ObserveSingleEvent always dispatches callback to UI thread (and I think all or almost all firebase callbacks do that). It does not capture synhronization context or something like that - just always dispatches callback to UI thread (remember - it's just a wrapper around native IOS code). So when you block your UI thread by waiting on Result - it will deadlock for obvious reasons, regardless of from which thread you call GetUsers. Links you mention describe another situation when called code captures current synhronization context, so they call that code from background thread which has no synhronization context and callbacks will not be posted to it. That's not the case here.
I am using async method as extension for StorageFile to return file's size. Problem is, this method deadlocks somehow my Windows Store app. Issue is within awaiting result from file.GetBasicPropertiesAsync. I am not very experienced in asynchronous programming, but I supposed await statement is there to prevent such situations. Does anyone see something obvious what I don't get?
Deadlock do not occur in debug, if I wait for some time with GetBasicPropertiesAsync.
Method:
public static async Task<string> GetSizeMB(this StorageFile file)
{
var properties = await file.GetBasicPropertiesAsync();
double sizeDouble = Convert.ToDouble(properties.Size) /1000000;
return $"{Math.Round(sizeDouble, 2)} MB";
}
Thanks in advance for hints.
If you look further up your call stack, you're almost certainly calling a task's Result or Wait member from the UI thread. This is not permitted on Windows Store applications, since it can freeze the UI thread.
I describe this kind of deadlock in detail on my blog, but the summary version is as follows:
When await has to (asynchronously) wait, by default it will first capture a "context". This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. Later, when the (asynchronous) wait is complete, the remainder of your async method continues executing on that captured context.
In this case, the context is the UI SynchronizationContext. Further up your call stack, another method calls GetSizeMB and gets back a task, and then (presumably) calls Result or Wait on that task. This is the actual cause of the deadlock, because that code is blocking the UI thread until GetSizeMB completes. But GetSizeMB cannot complete because it needs to resume executing on the UI thread.
The proper fix is to replace Result/Wait with await.
I came across some best practices for asynchronous programming using c#'s async/await keywords (I'm new to c# 5.0).
One of the advices given was the following:
Stability: Know your synchronization contexts
...
Some synchronization contexts are non-reentrant and single-threaded. This means only one unit of work can be executed in the context at a given time. An example of this is the Windows UI thread or the ASP.NET request context.
In these single-threaded synchronization contexts, it’s easy to deadlock yourself. If you spawn off a task from a single-threaded context, then wait for that task in the context, your waiting code may be blocking the background task.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
If I try to dissect it myself, the main thread spawns to a new one in MyWebService.GetDataAsync();, but since the main thread awaits there, it waits on the result in GetDataAsync().Result. Meanwhile, say the data is ready. Why doesn't the main thread continue it's continuation logic and returns a string result from GetDataAsync() ?
Can someone please explain me why there is a deadlock in the above example?
I'm completely clueless about what the problem is ...
Take a look at this example, Stephen has a clear answer for you:
So this is what happens, starting with the top-level method (Button1_Click for UI / MyController.Get for ASP.NET):
The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).
GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.
... Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete. For the UI example, the "context" is the UI context; for the ASP.NET example, the "context" is the ASP.NET request context. This type of deadlock can be caused for either "context".
Another link you should read: Await, and UI, and deadlocks! Oh my!
Fact 1: GetDataAsync().Result; will run when the task returned by GetDataAsync() completes, in the meantime it blocks the UI thread
Fact 2: The continuation of the await (return result.ToString()) is queued to the UI thread for execution
Fact 3: The task returned by GetDataAsync() will complete when its queued continuation is run
Fact 4: The queued continuation is never run, because the UI thread is blocked (Fact 1)
Deadlock!
The deadlock can be broken by provided alternatives to avoid Fact 1 or Fact 2.
Fix 1: Avoid 1,4. Instead of blocking the UI thread, use var data = await GetDataAsync(), which allows the UI thread to keep running
Fix 2: Avoid 2,3. Queue the continuation of the await to a different thread that is not blocked, e.g. use var data = Task.Run(GetDataAsync).Result, which will post the continuation to the sync context of a threadpool thread. This allows the task returned by GetDataAsync() to complete.
This is explained really well in an article by Stephen Toub, about half way down where he uses the example of DelayAsync().
I was just fiddling with this issue again in an ASP.NET MVC project. When you want to call async methods from a PartialView, you're not allowed to make the PartialView async. You'll get an exception if you do.
You can use the following simple workaround in the scenario where you want to call an async method from a sync method:
Before the call, clear the SynchronizationContext
Do the call, there will be no more deadlock here, wait for it to finish
Restore the SynchronizationContext
Example:
public ActionResult DisplayUserInfo(string userName)
{
// trick to prevent deadlocks of calling async method
// and waiting for on a sync UI thread.
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
// this is the async call, wait for the result (!)
var model = _asyncService.GetUserInfo(Username).Result;
// restore the context
SynchronizationContext.SetSynchronizationContext(syncContext);
return PartialView("_UserInfo", model);
}
Another main point is that you should not block on Tasks, and use async all the way down to prevent deadlocks. Then it will be all asynchronous not synchronous blocking.
public async Task<ActionResult> ActionAsync()
{
var data = await GetDataAsync();
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
A work around I came to is to use a Join extension method on the task before asking for the result.
The code look's like this:
public ActionResult ActionAsync()
{
var task = GetDataAsync();
task.Join();
var data = task.Result;
return View(data);
}
Where the join method is:
public static class TaskExtensions
{
public static void Join(this Task task)
{
var currentDispatcher = Dispatcher.CurrentDispatcher;
while (!task.IsCompleted)
{
// Make the dispatcher allow this thread to work on other things
currentDispatcher.Invoke(delegate { }, DispatcherPriority.SystemIdle);
}
}
}
I'm not enough into the domain to see the drawbacks of this solution (if any)
I have an ASP.NET MVC 3 site that connects to a WCF service. The WCF Service is independent from the site and is hosted in a Windows Service.
Most of the calls are synchronous, so it's not a problem to wait for the WCF to do it's thing.
However, one of those (already implemented) calls takes a bit too long, and, as it essentially does not output anything directly, I wanted to spin it on the service and forget about it.
So I changed my code from:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
to
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
which, as I understand should start an asynchronous request, and return immediately. Still, the execution is completely synchronous, and the UI is frozen until the operation concludes.
What obvious thing am I missing?
Update:
Also, note that I would prefer not to change the server implementation to an async one, just to de-synchronize the call to the service on the call-site.
Moreover, I've noticed that the StartSlowCalculation method finishes executing, but the server does not return a response until the service method finishes executing.
The WCF Service Proxy just does:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
so it's completely synchronous, however that shouldn't matter as it should be executed on an independent thread.
A task operation can run in the calling thread, it depends on taskScheduler decision. To help TaskScheduler make a right decision regarding long running call you can specify task creation option TaskCreationOptions.LongRunning.
And you can check whether task operation is running in a separate thread:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
BTW, are you using any kind of Task.Wait() operation? It will block calling thread as well.
EDIT:
You might find following post interesting Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
So try out using Task.Factory.StartNew() and specify cancellation token even you do not need it, sounds weird but it seems this guarantees that task will not be run eventually in the calling thread. Correct me If I wrong.
I've done this before.
The most robust way would be to use Asynchronous Controller's, or better yet an independant service such as a WCF service.
But in my experience, i've just needed to do "simple", one-liner task, such as auditing or reporting.
In that example, the easy way - fire off a Task:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
That's a simple example. You can fire off as many tasks as you want, synchronize them, get notified when they finish, etc.
For more details you can see this links.
https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx