MvvmCross ViewModel Start method async behavior clarification - async-await

In my ViewModel I load data in (overrided) Start method, like so:
public override async void Start()
{
base.Start();
await ProcessItems();
// or the following (no difference for Start method behavior)
await ProcessItems().ConfigureAwait(false);
}
However, it doesn't look like the await/async logic actually works with the method (I tested it with Android only, though).
"Doesn't work" means that right after calling my awaitable ProcessItems all the rest of ViewModel pipeline is called (like Initialize, ViewCreated, ViewAppearing etc.) before the awaitable method actually finished work.
Which brings up some further issues as the rest of methods expect the data initialization already finished.
So, what should I take into consideration here and how handle this situation.
Thanks!

The calling code can't await Start because it is returning void. Any exceptions being thrown in there are being swallowed. If the method returned Task or Task<T> then this would work as you expect. You pretty much never want to use async void except in an event handler. There is an MSDN article going further into detail as to why async void should be avoided.
This problem is fixed in MvvmCross 5 and later where you would do this same kind of initialization in Task Initialize method in place of this void Start method.

Since MvvmCross 5.0 there is a new lifecycle. https://www.mvvmcross.com/documentation/fundamentals/viewmodel-lifecycle#initialize
Please use Initialize for your stuff instead of Start.
Initialize: All heavy work should be run here. This method returns a Task, which means you can mark it as async and use await safely. If this method fails, the Navigate call that you are probably awaiting will fail, so you might want to catch that exception.
public async Task Initialize()
{
await base.Initialize();
await ProcessItems();
}

Related

Blazor - When to use Async life cycle methods

Is there any thumbrule for a beginner to understand when to use which life cycle methods, when developing a Blazor Server app.
OnInitialized() vs OnInitializedAsync()
OnParametersSet() vs OnParametersSetAsync()
OnAfterRender() vs OnAfterRenderAsync()
OnInitialized() vs OnInitializedAsync()
Prefer the simple OnInitialized() to set data without async, like message="hello";.
As soon as you have to call and await async methods, for instance on HttpClient, switch to OnInitializedAsync().
More rules of thumb:
do not use .Result or .Wait() on async methods
do not start async methods without awaiting them
do not use async void except in very rare cases.
When you get it wrong there will be an Error (can't await) or a Warning:
CS4032 The 'await' operator can only be used within an async method.
Is obvious, you should have used a *Async method. But do not 'fix' it by using async void or .Result.
CS1998 This async method lacks 'await' operators and will ...
means you should not have used the *Async method.
CS4014 Because this call is not awaited, ...
means you are not awaiting something you should.

Xamarin Async Constructor

For my application I need to fetch some data asynchronously and do some initialization for each page. Unfortunately, a constructor does not allow me to make asynchronous calls. I followed this article and put all of my code into the OnAppearing method. However, since then I ran into multiple issues since each platform handles the event a little bit differently. For example, I have pages where you can take pictures, on iOS the OnAppearing is called again every time after the camera is closed while Android doesn't. It doesn't seem like a reliable method for my needs, which is also described here:
Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation. For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.
I am searching for a method/way where I can perform my own initialization. The constructor would be perfect for that but I cannot perform anything asynchronously in there. Please do not provide me with any work arounds, I am searching for a solution that is the "recommended" way or maybe someone with a lot of experience can tell me what they are doing. (I also don't want to .Wait() or .Result as it will lock my app)
You can use Stephen Cleary's excellent NotifyTaskCompletion class.
You can read more how it works and what to do/don't in these cases in Microsoft's excellent Async Programming : Patterns for Asynchronous MVVM Applications: Data Binding. The highlights of this topics are:
Let’s walk through the core method
NotifyTaskCompletion.WatchTaskAsync. This method takes a task
representing the asynchronous operation, and (asynchronously) waits
for it to complete. Note that the await does not use
ConfigureAwait(false); I want to return to the UI context before
raising the PropertyChanged notifications. This method violates a
common coding guideline here: It has an empty general catch clause. In
this case, though, that’s exactly what I want. I don’t want to
propagate exceptions directly back to the main UI loop; I want to
capture any exceptions and set properties so that the error handling
is done via data binding. When the task completes, the type raises
PropertyChanged notifications for all the appropriate properties.
A sample usage of it:
public class MainViewModel
{
public MainViewModel()
{
UrlByteCount = new NotifyTaskCompletion<int>(
MyStaticService.CountBytesInUrlAsync("http://www.example.com"));
}
public NotifyTaskCompletion<int> UrlByteCount { get; private set; }
}
Here, the demo is about binding the returned asynchronous value to some bindable property, but of course you can you is without any return value (for simple data loading).
This may be too simple to say, but you CAN run asynchronous tasks in the constructor. Just wrap it in an anonymous Task.
public MyConstructor() {
Task.Run(async () => {
<Your code>
}
}
Be careful when doing this though as you can get into resource conflict issues if you accidentally open the page twice.
Another thing I like to do is use an _isInit flag, which indicates a first time use, and then never again.

For a Xamarin Forms application how should I decide what goes in the App constructor or the OnStart()?

Here's the code that I have:
public App()
{
InitializeComponent();
DB.CreateTables();
DB.GetSettings();
DB.PopulateTables();
SetResourceColors();
SetResourceDimensions();
MainPage = new MainPage();
activity = Helpers.Activity.Create();
VersionTracking.Track();
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
protected override void OnStart()
{
}
Can someone explain to me. Is there any difference between me placing the code such as I have in the constructor or in the OnStart() method? What's the normal way to do this?
I have been working with Xamarin.Forms for a long time now and this is how I and my fellow developers use the OnStart Method.
If you check the Microsoft documents it says the following about it :
OnStart - Called when the application starts.
So, first of all, you should know that there is no specific use of the OnStart method, to be very honest there is no major difference in between using the constructor or this lifecycle method because both get called on XF framework startup, first the constructor then the OnStart method.
Now let's come to the differences.
As Jason pointed out, the OnStart method is a lifecycle method and hence has a return type unlike the constructor, so you can even call an asynchronous piece of code in the OnStart method but you cannot do the same in the constructor as constructors cannot be asynchronous.
Which means if you have the below method:
public async Task<bool> IsSomeThingWorkingAsync(//SomeParams)
{
// Code
}
Now, this method cannot be asynchronously called from the constructor since constructors are forcefully synchronous and have no return types. But if you try doing that from the on start method it's quite easy and it will work. In this case, you use the OnStart method. Something like below:
protected override async void OnStart()
{
bool WasWorkSuccess=await IsSomeThingWorkingAsync();
//do something with the boolean
}
A constructor is intended to be used for wiring. In the constructor, you want to avoid doing actual work. You basically prepare the class to be used. Methods are intended to do actual work.
Note: There are no performance gains whatsoever by choosing one over the other - it's really a matter of preference and standard.
Please go through the details here
You can write the initialisation codes in App() constructor. But you need to be very careful abut registering events.
Reason is,
For example in Android, If the app is launched and it is in task list and if you try to launch the app again by clicking on app icon. The constructor of App() will call again. This will register the event multiple times and will create issues.
So for events I will suggest you to use overriden methods for registering events.
Again as Jason pointed it out, It is your personal preference where to write your code.

Simple Injector interception in async/await code

I am starting a new project and am thinking of using Simple Injector interception (https://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html) for tracing method entry/exit and logging parameters and return values etc. I have used this interceptor in the past and it works great. But my previous projects were not async/await. This new project has a lot of methods that are all async/await and I was wondering
will this interceptor work for async/await methods?
what changes are required in this interceptor to make it work for async/await methods?
I understand that decorators are a much better pattern than interception but writing a decorator for each and every interface that I want to trace is not something that I am looking forward to doing.
UPDATE:
I have tried this interceptor in my async/await code and it does inject my tracing code. However, I was getting weird results in some parts of my application. I didn't get chance to dig deeper into why disabling interception would make it work fine and why when interception was enabled it would not work as expected. It could very well be something wrong with my code.
I was hoping if someone, who has already used this interception extension in their code, would be able to point me in the right direction.
will this interceptor work for async/await methods?
Async code in C# is syntactic sugar on top of Task. This means that if your code needs to do anything useful after a call to an async method, you will have call ContinueWith on the returned Task (or use the C# syntax). If you take asynchronous into consideration in your interceptor, you won't be able to execute logic after the wrapped object.
So to make this work, you will have to explicitly check whether the wrapped method returns Task and if that's the case, you should make things async by hooking your 'after' code using ContinueWith.
This is one of the many reasons I consider interception to be inferior to using decorators. Decorators allow your code to be much cleaner, refrain from using reflection, give complete compile time support, give better performance, prevent having to depend on an interception library, and force you into a much more SOLID application design.
That said, the documentation's MonitoringInterceptor will look as follows when it takes asynchronicity into consideration:
class MonitoringInterceptor : IInterceptor
{
private readonly ILogger logger;
public MonitoringInterceptor(ILogger logger) {
this.logger = logger;
}
public void Intercept(IInvocation invocation) {
var watch = Stopwatch.StartNew();
// Calls the decorated instance.
invocation.Proceed();
var task = invocation.ReturnValue as Task;
if (task != null) {
invocation.ReturnValue = LogElapsedAsync(task, invocation, watch);
} else {
LogElapsed(invocation, watch);
}
}
private async Task LogElapsedAsync(Task task, IInvocation i, Stopwatch w) {
await task;
LogElapsed(i, w);
}
private void LogElapsed(IInvocation invocation, Stopwatch watch) {
var decoratedType = invocation.InvocationTarget.GetType();
this.logger.Log(string.Format("{0} executed in {1} ms.",
decoratedType.Name, watch.ElapsedMilliseconds));
}
}

Is it bad practice to mark void-returning view lifecycle methods like ViewDidLoad/OnCreate async?

Most of the articles on async/await best practices suggest that async void methods should be avoided unless the method is an event handler.
What are the best practices for handling situations where you need to call an async method during initialization of a view?
I've seen code that marks lifecycle methods such as ViewDidLoad, ViewWillAppear, OnCreate, OnResume etc as async void so that a method can be await-ed in the method body - but my gut reaction to this is that it is dangerous if the method is an override from the framework - since the consumer might not be aware of the context in which the method is being used internally.
An alternate approach could be to assign the result of the async method to a Task. Then await that Task before any dependent code runs:
Foo.cs:
async Task SomeMethodForInit()
{
//some code here for Init
}
Android Fragment:
Task _initTask;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_initTask = fooInstance.SomeMethodForInit();
}
...
//call this before doing anything dependent on that task
await _initTask;
Is this the right approach?
I like this post on async/await best practices. The biggest problem imho is from exceptions not getting handled properly when encountering async void.
To answer your question: Is there a specific reason why you have to use await or maybe can you choose a different approach to solving your problem? If you can, great, if not, the "downside" should be negligible.

Resources