Home > OS >  Initialize async data in ViewModel .NET MAUI
Initialize async data in ViewModel .NET MAUI

Time:02-04

Hope you all guys are doing great. I am new to MAUI .NET and MVVM pattern, I'm running through something that I don't seem to find an answer to solve my problem, Which is... For example:

public BotsViewModel(UiPathService _uiPathService)
{

    Title = "UiPath Bots";
    
    this.uiPathService = _uiPathService;
    
    //This is an async method which loads data on the view attached to the viewmodel
    
    GetTopBotsByLoSAsync();
}

I am not having a problem with loading data on initialization but while navigating and searching for better practices, I ran into that initializing data on a constructor is a bad practice and also Async data... How should i do this the right way, I followed allot of MAUI tutorials and all teachers seem to initialize data with the click of a button, but it doesn't feel the right way to me, I need to have all data in the page after is loaded with no user prompt to get it... so the only way i find to init data is this way I'm currently using, which is calling this async method (This method calls an API which fetch's data for my view) that is not being awaited in my constructor. Does anyone know how can I refactor this for better practices?

I need better practices please help haha

CodePudding user response:

I highly recommend using the .SafeFireAndForget() extension method found in the AsyncAwaitBestPractices NuGet Package.

It allows you to run an async method without needing to await it, while still ensuring best practices are being followed (e.g. you should await every Task and the library does this for you under the hood by leveraging one of the few valid use-cases of async void).

Full disclosure: I'm the author of this library, but it has over a million combined downloads with its companion library, the AsyncAwaitBestPractices.MVVM NuGet Package.

The code is all open-source and you're welcome to copy/paste the source code into your app if you don't want to add a 3rd Party Dependency: https://github.com/brminnick/AsyncAwaitBestPractices

Its GitHub repo also includes a deeper explanation, including videos I've made, on how async/await works and why I created this library.

using AsyncAwaitBestPractices;

public BotsViewModel(UiPathService _uiPathService)
{

    Title = "UiPath Bots";
    
    this.uiPathService = _uiPathService;
    
    //This is an async method which loads data on the view attached to the viewmodel
    
    GetTopBotsByLoSAsync().SafeFireAndForget();
}

CodePudding user response:

initializing data on a constructor is a bad practice and also Async data...

To be clear, blocking the UI thread waiting for the data to arrive is a bad practice, just like any other blocking of the UI. Instead, what you need to do is synchronously initialize the UI to a "Loading" state and start the asynchronous operation, and then when the data arrives, update the UI into a "Ready" state with the new data.

It appears your code is already following that general pattern, but there is a problem with how GetTopBotsByLoSAsync is called: any exceptions will be ignored. This is fine if GetTopBotsByLoSAsync has a top-level try/catch that updates the UI into an "Error" state.

Alternatively, you can use a "notify task" type like this one which allows you to use data binding to switch between "Loading", "Ready", and "Error" states. My original article on this type is here.

  • Related