My app contains a procedure which could be long-running. I would like to give users the opportunity to stop it.
The procedure is:
void longRunningProcedure()
(it does not access the file system or the Internet)
And within it, once certain variables are initialized, it calls doIt();
I tried this:
async void longRunningProcedure()
and within this procedure, I have tried:
await Task.Run(() => doIt());
and have tried:
await Task.Run(async () => await doIt());
But when the code reaches this point I get this error:
The selected debug engine does not support any code executing on the current thread (e.g. only native runtime code is executing).
Unhandled Exception:
Android.Util.AndroidRuntimeException: <Timeout exceeded getting exception details> occurred
The long-running code doesn't even run at all.
What to do?
I changed the void longRunningProcedure() to async void, like below:
async void runLongRunningProcedure()
{
await Task.Run(() => actualProcedure());
for my app, the actualProcedure() is just:
void actualProcedure()
Now, apart from this code, I have a variable,
bool cancelPressed
which starts off as false
I have a button and a menu item which sets this to true when pushed or clicked.
And this all works. I can kick off the procedure and stop it with the button or menu click.
There was another issue: The long running procedure writes data to one of the app's text boxes.
Doing that resulted in this error:
The selected debug engine does not support any code executing on the current thread (e.g. only native runtime code is executing).
SO, I had to modify the data writing section to this:
RunOnUiThread( () => {
txtBox.Text += modifiedData.ToString();
});
modifiedData is a StringBuilder type of variable.
And, this all works.
At the appropriate moment during the procedure I have:
if (cancelPressed == true) return
Just to be safe, I enclosed this in try/catch.
Of course if I wanted to notify the user that the procedure was cancelled (or anything else while it is running) via a Toast message I have to do this:
RunOnUiThread(() => {
MakeToast(Message);
return;
});
I have a procedure called MakeToast which handles the message formatting, etc.
I am developing an app using Xamarin.Forms to re-use as much code as possible.
Specifically, I have a static class that manages all the POST/GET requests to my Azure Web Server.
Everything single call works fantastically except for one call - this one:
public async static Task<Models.UserParkPosition> GetUserParkPositionForCurrentUserAsync()
{
var body = new JArray { App.User.Id };
var test = await AzureMobileServiceClient.Instance.MobileService.InvokeApiAsync<JArray, Models.UserParkPosition>(ConnectionsAPI, body, HttpMethod.Get, null);
return test;
}
The method above is called when the user presses a button - specifically like this:
private async Task OnGoingToTheParkClicked(object sender, EventArgs e)
{
bool success = false;
var already = await viewModel.AlreadyHavePendingRequestAsync());
Console.WriteLine("TEST");
throw new Exception();
}
When the debugger hits the "var test" line mentioned, above.... nothing happens. The code doesn't deadlock, the UI is still responsive, but the code never returns. I never see the "TEST" word and the exception is not even thrown... what happens??
All my other APIs are called in the same way, and are working correctly.
OTHER INFO:
- Same code works on UWP and Android
- The GET request arrives at the webservice, which responds in a timely fashion (< 1 sec)
Thanks to anyone who might help or even point me in the right direction!
Found the issue - InvokeApiAsync throws an exception which is not catched anywhere from any calling thread. It somehow just disappears without causing any error nor device log, nor crash. Weird, but that's how the world goes.
I want to link async method to a delegate command in prism framework in Xamarin.Forms and my question is how to do it?
Is below solution correct? Is there exist any pitfall? (deadlock, UI slow or freezing, bad practices, ...)
{ // My view model constructor
...
MyCommand = new DelegateCommand(async () => await MyJobAsync());
...
}
private async Task MyJobAsync()
{
... // Some await calls
... // Some UI element changed such as binded Observable collections
}
You can use async void directly. However, a few notes from my experience...
The structure of your code is: start asynchronous operation and then update UI with the results. This implies to me that you would be better served with a NotifyTask<T> kind of approach to asynchronous data binding, not commands. See my async MVVM data binding article for more about the design behind NotifyTask<T> (but note that the latest code has a bugfix and other enhancements).
If you really do need an asynchronous command (which is much more rare), you can use async void directly or build an async command type as I describe in my article on async MVVM commmands. I also have types to support this but the APIs for these are more in flux.
If you do choose to use async void directly:
Consider making your async Task logic public, or at least accessible to your unit tests.
Don't forget to handle exceptions properly. Just like a plain DelegateTask, any exceptions from your delegate must be properly handled.
Just have a look at this link if you're using Prism Library: https://prismlibrary.com/docs/commands/commanding.html#implementing-a-task-based-delegatecommand
In case you want to pass a CommandParameter to DelegateCommand, use in the DelegateCommand variable declaration this syntax
public DelegateCommand<object> MyCommand { get; set; }
In the constructor of the ViewModel initialize it this way:
MyCommand = new DelegateCommand<object>(HandleTap);
where HandleTap is declared as
private async void HandleTap(object param)
Hope it helps.
As has already been mentioned the way to handle async code with delegate command is to use async void. There has been a lot of discussion on this, far beyond just Prism or Xamarin Forms. The bottom line is that ICommand that both the Xamarin Forms Command and Prism DelegateCommand are limited by ICommand's void Execute(object obj). If you'd like to get more information on this I would encourage you to read the blog by Brian Lagunas explaining why DelegateCommand.FromAsync handler is obsolete.
Generally most concerns are handled very easily by updating the code. For example. I often hear complaints about Exceptions as "the reason" why FromAsync was necessary, only to see in their code they never had a try catch. Because async void is fire and forget, another complaint I've heard is that a command could execute twice. That also is easily fixed with DelegateCommands ObservesProperty and ObservesCanExecute.
I think the two main problems when calling an asynchronous method from one that executes synchronously (ICommand.Execute) are 1) denying to execute again while previous call is still running 2) handling of exceptions. Both can be tackled with an implementation like the following (prototype). This would be an async replacement for the DelegateCommand.
public sealed class AsyncDelegateCommand : ICommand
{
private readonly Func<object, Task> func;
private readonly Action<Exception> faultHandlerAction;
private int callRunning = 0;
// Pass in the async delegate (which takes an object parameter and returns a Task)
// and a delegate which handles exceptions
public AsyncDelegateCommand(Func<object, Task> func, Action<Exception> faultHandlerAction)
{
this.func = func;
this.faultHandlerAction = faultHandlerAction;
}
public bool CanExecute(object parameter)
{
return callRunning == 0;
}
public void Execute(object parameter)
{
// Replace value of callRunning with 1 if 0, otherwise return - (if already 1).
// This ensures that there is only one running call at a time.
if (Interlocked.CompareExchange(ref callRunning, 1, 0) == 1)
{
return;
}
OnCanExecuteChanged();
func(parameter).ContinueWith((task, _) => ExecuteFinished(task), null, TaskContinuationOptions.ExecuteSynchronously);
}
private void ExecuteFinished(Task task)
{
// Replace value of callRunning with 0
Interlocked.Exchange(ref callRunning, 0);
// Call error handling if task has faulted
if (task.IsFaulted)
{
faultHandlerAction(task.Exception);
}
OnCanExecuteChanged();
}
public event EventHandler CanExecuteChanged;
private void OnCanExecuteChanged()
{
// Raising this event tells for example a button to display itself as "grayed out" while async operation is still running
var handler = CanExecuteChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
}
async void
I personally would avoid "async void" at all cost. It is impossible to know from the outside when the operation has finished and error handling becomes tricky. In regards to latter, for instance writing an "async Task" method which is called from an "async void" method almost needs to be aware of how its failing Task is propagated:
public async Task SomeLogic()
{
var success = await SomeFurtherLogic();
if (!success)
{
throw new DomainException(..); // Normal thing to do
}
}
And then someone writing on a different day:
public async void CommandHandler()
{
await SomeLogic(); // Calling a method. Normal thing to do but can lead to an unobserved Task exception
}
Is UI thread running DelegateCommand and background threads running await expression?
Yes, the UI thread runs the DelegateCommand. In case of an async one, it runs until the first await statement, and then resumes his regular UI thread work. If the awaiter is configured to capture the synchronization context (that is, you do not use .ConfigureAwait(false)) the UI thread will continue to run the DelegateCommand after the await.
Is UI thread running DelegateCommand and background threads running await expression?
Whether the "await expression" runs on a background thread, foreground thread, a threadpool thread or whatever depends on the api you call. For example, you can push cpu-bound work to the threadpool using Task.Run or you can wait for an i/o-operation without using any thread at all with methods like Stream.ReadAsync
public ICommand MyCommand{get;set;}
//constructor
public ctor()
{
MyCommand = new Xamarin.Forms.Command(CmdDoTheJob);
}
public async void DoTheJob()
{
await TheMethod();
}
public DelegateCommand MyCommand => new DelegateCommand(MyMethod);
private async void MyMethod()
{
}
There are no pitfalls. A void return type in async method was created especially for delegates. If you want to change something, that has reflected on UI, insert relevant code in this block:
Device.BeginOnMainThread(()=>
{
your code;
});
Actually, ICommand and DelegateCommand pretty similar, so an above answer is quite right.
I would like to make a service call to a REST API to check a value and if true, take the user to a new page. Instead of presenting a view controller, I'd like to just use a segue that I have wired up.
The service call to check the value is async Task, and I am calling it when a segue tries to fire (when the user presses the button)
public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender)
{
.. run check here, and return true or false to fire the segue
}
The problem is that C# wants me to modify this method to be async Task or async void or async Task but that breaks the 'override' since i'm no longer overriding.
What is the correct approach to handle a call with async programming, and then once the call finishes, take the user away?
Thanks so much.
You can try to start your method in a Task and when finished take the user away.
Example:
var someTask = Task.Run(async () =>
{
var EventModal = await Method();
await Navigation.PushAsync(Page(EventModal.Stuff));
});
I'm trying to implement async calls with the new Async/Await pattern in visual studio 2012. When i set up my form (using the form designer) and then try to use an async method as an event handler, the compiler complains that the function doesn't return void.
The method is supposed to return a Task; that's the whole point. I cant figure out how to tell the form designer that this isn't a regular event handler. Has anyone run into this issue? should i quit using the form designer for Rapid Development?
You have to use an async void method for the event handler, instead of async Task. Being able to wire up event handlers to async methods is the entire reason async void is allowed.
For example, if you want to use a button click handler, you'd write it like:
private async void button_Click(object sender, EventArgs e)
{
bool success = await CallSomeMethodAsync();
if (success)
{
// Do something here, etc...
}
}