I just started playing with my fresh Raspberry Pi 3 and Win10 IOT.
I tried a little project but encountered some problems with async/await statements.
I am not new to C#, nor with await/async, but it is my first time with UWP so I may miss some tricks for this platform compairing to the WinForms/WPF environment.
(FYI, I haven't access to a Win10 developpement machine for the moment, so below snippets may not compile right away)
Here is the standard template for a headless application on the Rpi :
public async void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.GetDeferral();
await DoSomethingAsync();
// Other irrevelant stuff then...
defferal.Complete();
}
And then an async method :
private async Task DoSomethingAsync()
{
// Something done async
await Task.Delay(1000);
} // <--- Hangs here
When deploying the app to the Pi, it enters the DoSomethingAsync method and execute its content without problem.
My issue is that the app hangs at the exiting semicolon.
Do we need to use the CoreDispatcher, the ThreadPool, or a simple new TaskFactory().StartNew(async () => { await DoSomethingAsync(); }); ?
What I don't understand is the use of the await/async should execute my method on an other thread, but it hangs the same way as if it was waiting for UI to process messages queue (WinForms/WPF background here :) )
Thank you in advance.
EDIT : This snippet works if I remove all the async stuff to make it synchronously running.
I don't see Complete() method on defferal in your code, try this:
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroudTaskDefferal defferal = taskInstance.GetDeferral();
await DoSomethingAsync();
// Other irrevelant stuff then...
defferal.Complete();
}
That could be problem with hanging, application's waiting for signal that async operations are completed.
If you remove all the breakpoints, add debugging logs like
`System.Diagnostics.Debug.WriteLine`
The debug message would show everything is working all fine.
The hang only happens when you do the remote debugging with VS.
I suggest you open an user voice request.
Related
I'm calling a 3rd party library from my C# code, and have found that ctx.CreateSiteAsync(communicationSiteInfo).Wait(); works well, while await ctx.CreateSiteAsync(communicationSiteInfo); causes the application to crash. As .Wait() to the best of my knowledge causes the thread to block, I'm interested inn getting the await approach to work.
Here an extract from my code to put the above calls in context:
public async Task createSite(string base_url, SiteConfig siteConfig) {
using(var ctx = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(base_url, this.applicationId, this.applicationSecret)) {
ctx.Load(ctx.Web, p => p.Title);
ctx.ExecuteQuery();
CommunicationSiteCollectionCreationInformation communicationSiteInfo = new CommunicationSiteCollectionCreationInformation {
Title = siteConfig.title,
Url = siteConfig.url,
SiteDesign = siteConfig.siteDesign,
Description = siteConfig.description,
Owner = siteConfig.ownerEmailAddress
};
try {
// This works: ctx.CreateSiteAsync(communicationSiteInfo).Wait();
await ctx.CreateSiteAsync(communicationSiteInfo);
} catch....
If I'm not mistaking, the function I'm calling it this one: ClientContextExtensions.cs.
I'm pretty new to C#, so perhaps the reason for the application crashing is obvious, but I can't see why the await wouldn't work, as the function I'm calling has async Task in it's definition.
EDIT: The weird thing regarding the exception is that the application simply crashes, and the catch clause is never reached. I don't know, but maybe this has something to do with threading or context or something in that the exception thrown in the async function call are not returned to the current thread. The application crashes on the await ctx.CreateSiteAsync(communicationSiteInfo); call.
EDIT 2: It looks as though I can simplify the issue at hand, but using this as an example instead:
public async Task StartMessageQueuePollAsync()
{
while (true)
{
await Task.Delay(1000).ConfigureAwait(false);
}
This causes the code to crash on await Task.Delay(1000).ConfigureAwait(false);. If is instead use Task.Delay(1000).Wait(), the code works as expected.
I see your answer, but I don't think that's the root cause. It's perfectly fine to use static async Task Main(), as long as your project is using C# 7.0 or higher (when that was introduced). If changing that (and making everything else synchronous, as you'd have to after removing async) made the symptom go away, then that means that somewhere along your call stack, you were missing an await.
For example, this works just fine:
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
Console.WriteLine("Hello.");
await Pause();
Console.WriteLine("All done");
}
public static async Task Pause() {
await Task.Delay(1000);
Console.WriteLine("Done pausing");
}
}
But if you remove the await in Main, then the application would end before "Done pausing" is printed. This is because async methods run synchronously at first, but return at the first await that acts on an incomplete Task. (Pause() returns a Task when it hits await Task.Delay(1000) - before the waiting is completed)
So if you don't await an async method, then your code will just move on to the next line before the work is done. Sometimes you actually want this, but often not.
Since it otherwise runs synchronously, replacing the await with .Wait() would halt the thread and the method would not return, making it suddenly "work".
In your code, that means that either you weren't awaiting createSite() or weren't awaiting whatever called the method that called createSite(), etc.
Microsoft has a series of very well-written articles about asynchronous articles that are worth reading. Start here: Asynchronous programming with async and await
Thanks for the comments on my initial post. I got it working now, and believe it's because of I defined the Main method to be async, like this:
static async Task Main().
My application is based on WPF.
Task is I need to show a custom busy indicator while something is working in the main window ( because the app UI will be freezed untill it complete the task). So what I particularly want is as below
// Code in main window
CustomBusyIndicator.ShowDialog();
//....
//..code that takes time
//....
CustomBusyIndicator.Close();
So I must implement a window which must be flexible to call anywhere in my main application to indicate busy.
Here two points should be kept in mind,
1. When i show CustomBusyIndicator, in background the main window should be running it's task
2. When i show CustomBusyIndicator, the CustomBusyIndicator should be always on top of main window, user must not be able to use the main window, if he switch to other application using Start+tab or something and again when he switch back to my application,the CustomBusyIndicator should be on top(if it is not closed).
When the task is completed I should be able call just close() method to close the CustomBusyIndicator from the main window as shown in code.
Easy to solve
public async void Button1_Click(Object sender, RoutedEventArgs e)
{
// get a task for the dialog, but do not await here its completion
var dialogTask = CustomBusyIndicator.ShowDialogAsync();
// await the completion of the lengthy operation
await SomeLengthOperationAsync();
// close the dialog
CustomBusyIndicator.Close();
// now await the completion of the dialog task
await dialogTask;
}
and the extension is
public static class WindowExtensions
{
public static async Task<bool?> ShowDialogAsync( this Window window )
{
await Task.Yield();
return window.ShowDialog();
}
}
If you don't know how to work with async await, just move your long running logic in a backgroundworker. There are several options for making the backgroundworker communicate without problems with the main GUI thread.
Based on your question and your level of experience I think you are way over your head with async wait. But Rufo's solution is fine too.
Google is your friend, There is a lot of information about using the backgroundworker and about async await too. It will just take a bit longer to fully grasp the potential of async await. Async await is btw not a solution for everything. I ran into a situation today where I ran in a database with EF6 that simply says it does not support async operations. Works perfectly well with sql server but this was pervasive. Total dissapointment because now me too have to use a backgroundworker where my first idea was async await.
The idea behind async await, is that the gui thread is not blocked if you are doing a long running task. It is more like a waitpoint where it will continue if that long operation is finished.
Other options are to use RX, but that difficulty level increases again.
Use the backgroundworker and you are fine, and your gui is never blocked. You can even cancel the work of the backgroundworker. Excellent solution for you.
Hello I have next problem with WCF. I generate my client proxy class with "task-based" async mode.
With sync methods all works good, but when I call async method (void or not - irrelevant) and close my WPF MainWindow (through cross on title bar), window closed but process not killed. And this happen only after async calls.
i try this:
var client = new Service.ServiceClient();
await client.syncWithDevicesAsync();
client.Close();
and with 'using':
using (var client = new Service.ServiceClient())
{
await client.syncWithDevicesAsync();
}
I've seen similar questions, but I could not understand them, please explain why this is going. Thx for help.
UPD: In debug thread window I saw when I call async method, created 4 threads, but after response released only 3.. GC.Collect() in close window event not help.
UPD2: after Julian answer I try next:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var proxy = new ServiceReference1.ServiceClient();
var photo = await proxy.getEmployeePhotoAsync(12);
label.Content = photo.Length; //everything is good, label show correct size. So the asynchronous method is completed?
proxy.Close();
//Environment.Exit(0); //- if uncomment window freeze forever. label nothing show.
}
and try this:
await Task.Run(async () =>
{
var photo = await proxy.getEmployeePhotoAsync(12);
Application.Current.Dispatcher.Invoke(() =>
{
label.Content = photo.Length;
});
});
UPD3: Oh..Now I am completely stuck. I download github example by Mahesh Sabnis. and the same behavior, the process hangs in task Manager after closing. Can someone tested at itself?
Using async methods with Task.Run:
queues that Task for execution on a threadpool thread. Threads execute in the
context of the process (eg. the executable that runs your application)
thus it's not running on the UI Thread (SO)
I presume that in your case some async method is still running (probably even looping) in the background after you have closed the WPF window and the UI thread stopped. Consequently the process is still running.
You could pass a CancellationToken to the background task(s) and then call Cancel in the application exit event.
As a last resort you could also call the System.Environment.Exit() method which terminates the process.
I'm not sure anyone else face this, but still I will write an answer. I first encountered this..
Problem was in my pc or VS2013.. I reboot my pc and all work with:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var proxy = new ServiceReference1.ServiceClient();
var photo = await proxy.getEmployeePhotoAsync(12);
label.Content = photo.Length;
proxy.Close();
}
I am trying to sleep my app for any milliseconds.
Developing simple app (just for fun) and I want that after my click works timer.
Thread.Sleep(8000);
Don't worked
new CountdownTimer(30000,1000);
not worked.
Is it so difficult?
You should be able to use:
await Task.Delay(x);
With x being milliseconds. You will evidently also need to be an an Async method for awaiting to be valid:
public async void Method1()
{
//etc.
await Task.Delay(x);
}
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.