How do run await in background in window phone? - c#

I want to run a method on background when app is closed.
async private void()
{
var bgw = new BackgroundWorker();
bgw.DoWork += (s,v) =>
{
string temp= await doSomething();
};
bgw.RunWorkerCompleted += (s,v) =>
{
//...
};
bgw.RunWorkerAsync();
}
It produces the following error
the await operator can only be used within an async lambda expression.
How do I fix it?

DoWork cannot be async. I recommend you use Task.Run instead:
async private void X()
{
await Task.Run(() => doSomething());
//...
}
However, you may need to call Wait instead of await since this is done at application shutdown.

Related

Can the Elapsed callback of a System.Timers.Timer be async?

Is it possible (or even reasonable) to make the callback of a System.Timers.Timer an async method? Something like:
var timer = new System.Timers.Timer
{
Interval = TimeSpan.FromSeconds(30).TotalMilliseconds,
AutoReset = true
};
timer.Elapsed += async (sender, e) => { /* await something */ };
timer.Start();
It compiles (obviously a good place to start), but I'm not sure I understand the consequences. Will the timer await the callback before resetting the timer?
Will the timer await the callback before resetting the timer?
No. There's nothing it could await, because the signature of ElapsedEventHandler has a void return type.
In other words, your code is equivalent to:
var timer = new System.Timers.Timer { ... };
timer.Elapsed += Foo;
timer.Start();
...
private async void Foo()
{
...
}
Whether that's acceptable for you or not will depend on your context. In general, having async void methods or anonymous functions makes them harder to test and reuse - but the ability was precisely given for the sake of event handlers... You should consider how errors will be propagated though.
The title of the question is specifically about Timers, but if we look at it as "How to call an async method after some time?" then you could do it without using a timer.
var task2 = Task.Run(async () => {
while (true)
{
try
{
await MyMethod2();
} catch
{
//super easy error handling
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
});
...
public async Task MyMethod2()
{
//async work here
}
Please note however that this will have different timing (timer will be called at an interval, the code above will be called every (run time + sleep_time), but even if MyMethod2 takes a long time it it won't be called twice. Having said that, you can calculate how long to await for to run 'every x minutes'.
Actually, you can.
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += async (x, y) => { await Task.Delay(1); };
The solution that proposed #tymtam doesn´t wait until MyMethod2 has ended.
I think it would be better to use this. An example with two async tasks, when both has finised, wait 5 seconds and execute again the two tasks:
var task2 = Task.Run(async () => {
while (true)
{
try
{
var task1 = MyMethod1();
var task2 = MyMethod2();
List<Task> allTasks = new List<Task> { task1, task2 };
while (allTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(allTasks);
if (finishedTask == task1)
{
Console.WriteLine("MyMethod1 has ended");
}
else if (finishedTask == task2)
{
Console.WriteLine("MyMethod2 has ended");
}
tareas.Remove(finishedTask);
}
//Here only when finished all task
} catch
{
//super easy error handling
}
//Wait until next cycle
await Task.Delay(TimeSpan.FromSeconds(5));
}
});
...
public async Task MyMethod1()
{
//async work here
}
public async Task MyMethod2()
{
//async work here
}

C# Await in a delegate call

I have a function :
public async Task DoStuff()
{
await DoSomethingAsync();
}
I need to call it from code running this:
list.ItemTapped += async (sender, e) =>
{
file.WriteAllBytes(reportPdf, data, () => **await** file.DoStuff());
};
But the await is not allowed in the Action file.DoStuff called in the above???
While GazTheDestroyer's answer is correct, there's no reason for the lambda expression to be marked async and to use an await since file.DoStuff already returns a Task and fits the Func<Task> delegate:
list.ItemTapped += async (sender, e) =>
{
file.WriteAllBytes(reportPdf, data, () => file.DoStuff());
};
It would also slightly improve performance since there's no reason to construct the state machine required for an async-await method/delegate.
Your second lambda is not marked async
list.ItemTapped += async (sender, e) =>
{
file.WriteAllBytes(reportPdf, data, async () => await file.DoStuff());
};
This depends on file.WriteAllBytes() allowing a Func<Task> to be passed in. An Action will not be enough.

Call a function periodically using BackgroundWorker

I have a C# windows form application. I want to update some labels by fetching information from the web. I want to call a function periodically using BackgroundWorker.
public partial class OptionDetails : Form
{
static System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
static void fun()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{ // some work }
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{ // on completion }
}
If I use Timer, the UI hangs. How do I use BackgroundWorker to call worker_DoWork periodically?
My actual code:
public partial class myform: Form
{
public myform()
{
InitializeComponent();
}
public async Task Periodic(Action func, TimeSpan period, CancellationToken token)
{
while (true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
func();
// asynchronously wait
await Task.Delay(period);
}
}
public async void hello()
{
await Periodic(getCurrentInfo, TimeSpan.FromSeconds(2), CancellationToken.None);
}
private void myform_Load(object sender, EventArgs e)
{
hello();
}
private void getCurrentInfo()
{
WebDataRetriever wdr = new WebDataRetriever();
string name = "name";
string url = String.Empty;
string[] prices = new string[2];
bool urlExists = url.TryGetValue(name, out url);
if (urlExists)
{
wdr.processurl(); // time consuming function
prices[0] = wdr.price1;
prices[1] = wdr.price2;
System.Globalization.NumberFormatInfo nfo = new System.Globalization.CultureInfo("en-US", false).NumberFormat;
if (prices != null)
{
// change labels
}
}
}
}
The simplest solution for what you need is probably to use a Timer to kick off BackgroundWorker, but using async/await I believe results in a more compact and elegant solution.
The solution below is an asynchronous method, for which the compiler generates a state machine. When the asynchronous method Periodic is invoked it starts executing up until the first await statement. In this case this is:
await Task.Delay(period);
The expression awaited returns an awaitable, which is in this case a Task, but it can be anything that has a method GetAwaiter which returns a type implementing the INotifyCompletion interface or the ICriticalNotifyCompletion interface.
If this task is complete the method continues executing synchronously, if the task is not complete the method returns. Once the task is complete, execution of the method resumes after that await statement in the same SynchronizationContext. If you called this from a GUI thread, execution will resume in the GUI thread, but for your case it will resume on a ThreadPool thread because console apps do not have a SynchronizationContext.
Task.Delay(period) returns a Task that becomes complete when the period elapses. I.e. it is like an asynchronous version of Thread.Sleep so execution of the while loop resumes after period expires.
The end result is that the loop runs forever periodically checking for cancellation (in which case an OperationCancelledException is thrown) and executing func.
public static async Task Periodic(Action func, TimeSpan period, CancellationToken token)
{
while(true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
func();
// asynchronously wait
await Task.Delay(period);
}
}
In a GUI app you can use it like this:
await Periodic(() => /* do something clever here*/, TimeSpan.FromSeconds(1), CancellationToken.None);
The main method of a console app cannot be asynchronous so you cannot use await but you can call Wait() on the result instead to run it indefinitely and prevent the application from exiting.
void Main()
{
Periodic(() => Console.WriteLine("Hello World!"), TimeSpan.FromSeconds(1), CancellationToken.None).Wait();
}
Care must be taken when calling Wait() in a GUI app as it can result in a deadlock.
Update
You may also benefit from having an overload of Periodic that takes an async func, in case you have an expensive time consuming function you want to run in the background.
public async Task Periodic(Func<Task> func, TimeSpan period, CancellationToken token)
{
while (true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
await func();
// asynchronously wait
await Task.Delay(period);
}
}

Call two or more functions one after another

I want to call two or more methods after another. When One function execution get's completed I need to call another method. Basically I am trying to implement the backup functionality in my app. I am developing Windows Phone app which take backup of contacts, images, video. I have created the method for each of these. When backup of contacts is completed then I want to call images method. I have created different functions for these. How can I call these function one after another?
I have tried something like this.
// Constructor
public MainPage()
{
InitializeComponent();
UploadImagesThread = new Thread(UploadImages);
UploadContactsThread = new Thread(UploadContacts);
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
On Upload button click
if (chkContacts.IsChecked.Value)
{
Dispatcher.BeginInvoke(() =>
{
SystemTray.ProgressIndicator.Text = "Searching contacts...";
});
UploadContactsThread.Start();
}
if (chkImages.IsChecked.Value)
{
Dispatcher.BeginInvoke(() =>
{
SystemTray.ProgressIndicator.Text = "Compressing images...";
});
UploadImagesThread.Start();
}
But It will not help me. How do I emplement? My UploadContact method has Async method call like this
Contacts objContacts = new Contacts();
objContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(objContacts_SearchCompleted);
objContacts.SearchAsync(string.Empty, FilterKind.None, null);
Use Task.ContinueWith() to chain up the calls.
You can have a look here: http://msdn.microsoft.com/de-de/library/dd321405(v=vs.110).aspx.
Applied to your problem, this should do the trick:
Task.Factory.StartNew(UploadImages).ContinueWith(UploadContacts);
Try using Tasks, which will let you give you a thread pool for free. You can't do this in a constructor but you could override you OnNavigatedTo Mehtod:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await Task.Run(() => { UploadImages(); });
await Task.Run(() => { UploadContacts(); });
}
The await will ensure that the contacts will start uploading after your images are completed. You could also check out background uploading which means your app will not have to run while the action is completing.
Your description of the problem (call one method after another?) is not very clear, but looking at your code, I suppose you want to wait for the UploadImagesThread thread to complete before starting the UploadContactsThread.
Use tasks and the async/await keywords like this:
private async void OnButtonClick(object sender, ...)
{
if (chkContacts.IsChecked.Value)
{
SystemTray.ProgressIndicator.Text = "Searching contacts...";
await Task.Run(() => UploadImages());
}
if (chkImages.IsChecked.Value)
{
SystemTray.ProgressIndicator.Text = "Compressing images...";
await Task.Run(() => UploadContacts());
}
}
Note: assuming your 2nd block of code is running on the UI thread, you shouldn't need to use BeginInvoke.
Edit
In response to your recent changes: you need a redesign. Try this:
private async void OnButtonClick(object sender, ...)
{
bool uploadContacts = chkContacts.IsChecked.Value;
bool uploadImages = chkImages.IsChecked.Value;
//use this if the continuation runs on the UI thread
Action continuation = async () => {
if(uploadImages) {
SystemTray.ProgressIndicator.Text = "Compressing images...";
await Task.Run(() => UploadImages());
}
};
//OR this if it doesn't
Action continuation = () => {
if(uploadImages) {
Dispatcher.BeginInvoke(() => SystemTray.ProgressIndicator.Text = "Compressing images...");
UploadImages();
}
};
if (uploadContacts)
{
SystemTray.ProgressIndicator.Text = "Searching contacts...";
UploadContacts(continuation);
}
}
private void UploadContacts(Action continuation)
{
Contacts objContacts = new Contacts();
//when the search has finished, trigger your event handler AND the continuation task, which will upload the images
objContacts.SearchCompleted += objContacts_SearchCompleted;
objContacts.SearchCompleted += (sender, args) => continuation();
objContacts.SearchAsync(string.Empty, FilterKind.None, null);
}
Try something like that :
bool backContact = chkContacts.IsChecked.Value;
bool backImages = chkImages.IsChecked.Value;
Task.Factory.StartNew(() =>
{
if (backContact) {
Dispatcher.BeginInvoke(() =>
{
SystemTray.ProgressIndicator.Text = "Searching contacts...";
});
UploadContacts;
});
}).ContinueWith(() =>
{
if (backImages) {
Dispatcher.BeginInvoke(() =>
{
SystemTray.ProgressIndicator.Text = "Compressing images...";
});
UploadImages;
}
}

Can I wrap Task.Run under another Task.Run()?

I have a method HandleAcceptedConnection that is under Task.Run() that i want to run asynchronously(in another separate thread). I tried declaring HandleAcceptedConnection as async method and dont call await but it doesnt seem to run asynchronously. I can confirm that I can have Task.Run()(by watching the thread id) under another Task.Run() but is that recommended?
private async void Start_Click(object sender, RoutedEventArgs e)
{
var task = Task.Run(() =>
{
while (isContinue)
{
var handler = listener.Accept();
// handle connection
Log("Before");
Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId);
// i want to run method below asynchronously. i want to
// wrap it under Task.Run() but i am already under
// Task.Run(). i set HandleAcceptedConnection as async. i thought by not
// calling await on HandleAcceptedConnection, HandleAcceptedConnection
// is asynchronous
HandleAcceptedConnection(handler);
Log("After");
isContinue = true;
}
});
await task;
}
private async Task HandleAcceptedConnection(Socket handler)
{
Log("ThreadId HandleAcceptedConnection " + Thread.CurrentThread.ManagedThreadId);
Log("Under HandleAcceptedConnection");
Thread.Sleep(10000);
}
When i run this, logs says
Before
Under HandleAcceptedConnection
After
i want
Before
After
Under HandleAcceptedConnection
i want HandleAcceptedConnection to be run asynchronously. Should i wrap it under another Task.Run or it is already asynchronous?
Did you try
private async Task HandleAcceptedConnection(Socket handler)
{
Thread.Sleep(1000);
Log("Under HandleAcceptedConnection");
}
Because doing something on another thread doesn't mean it'll be delayed.
You should be using AcceptTcpClientAsync, then you won't need extra threads. Check this answer for an example. Don't use a synchronous API when there is a naturally asynchronous version of it available.
Updated to address the comment. Nothing prevents you from using Task.Run from inside Task.Run, you code might look like this (untested):
private async void Start_Click(object sender, RoutedEventArgs e)
{
var connectionTasks = new List<Task>();
Func<Task> handleConnection = async () =>
{
var connectionTask = Task.Run(() => HandleAcceptedConnection(handler));
connectionTasks.Add(connectionTask);
await connectionTask;
connectionTasks.Remove(connectionTask);
};
var task = Task.Run(() =>
{
while (isContinue)
{
var handler = listener.Accept();
// handle connection
Log("Before");
Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId);
var connectionTask = handleConnection();
Log("After");
isContinue = true;
}
});
await task;
}

Categories

Resources