awaiting multiple calls using Models

97 views Asked by At

I have a project. I'm working on where a user can have multiple accounts tied to his/her profile. However, to get the account number and account name, there is an endpoint to call. To get the account balance for each account number, there is another endpoint to call. Now here is my problem. According to the design, I need to place the account number and the acct balance on each card as the account can be more than one. So, my question is, how best can I achieve this? making a call to get the account details then picking each account number to make another call that will return the acct balance for that particular account number.

Here are my models:

public class MyAccount
{
    public string linkerId { get; set; }
    [JsonProperty("accountDetails")]
    public AccountDetails Details { get; set; }
    public AcctUserDetails acctUserDetails { get; set; }
    public LinkedBy linkedBy { get; set; }
    public string requestTimestamp { get; set; }
    
}

public class Account
{
    [JsonProperty("payload")]
    public List<MyAccount> Accounts { get; set; }
}
public class AccountDetails
{
    string acctBalance;

    [JsonProperty("accountNumber")]
    public string AccountNumber { get; set; }

    [JsonProperty("accountName")]
    public string AccountName { get; set; }
    public string phoneNumber { get; set; }
    public string email { get; set; }

    [JsonProperty("accountType")]
    public string AccountType { get; set; }
    public string Balance
    {
        get
        {
            foreach (var accountNumm in AccountNumber)
            {
                MessagingCenter.Send<object, string>(this, "acctNo", AccountNumber);
                
            }
            MessagingCenter.Subscribe(this, "myAcctNo", (object obj, string theBalance) =>
                {
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        acctBalance = theBalance;

                    });

                });
            var newBall = acctBalance;
            return newBall;
        }
        set { Balance = value; }
    }
}

Also, My ViewModel makes the call to the API to get all accounts.

private async void LoadMyAccounts()
    {
        IsBusy = true;
        HttpClient client = new HttpClient();
        var url = Constant.GetLinkedAccountsUrl;
        var response = await client.GetAsync(url);

        var json = await response.Content.ReadAsStringAsync();

        Account userAccounts = JsonConvert.DeserializeObject<Account>(json);
        var sorted = userAccounts.Accounts;
        //getTrans = userTransactions
        var allAccounts = new ObservableCollection<MyAccount>(sorted);
        AccountsData = allAccounts;

        IsBusy = false;


    }

then I have a service class that sends and subscribes to the account number being sent from the model. Here is my serviceClass :

 public async void GetBalance()
    {
        HttpClient client = new HttpClient();
        var url = Constant.GetAcctBalanceUrl + acctBalance;
        var response = await client.GetAsync(url);

        var json = await response.Content.ReadAsStringAsync();

        if (response.IsSuccessStatusCode)
        {
            var pro = JsonConvert.DeserializeObject<AcctModel>(json);
            var newBal = pro.Balances;
            Constant.MyBalance = newBal;
            var acctNo = newBal.accountBalance;
            MessagingCenter.Send<object, string>(this, "myAcctNo", acctNo);
        }

    }

Please anyone has an idea how best to go about this or what to do to achieve the desired result,enter image description here

2

There are 2 answers

1
Arcanox On

Your model should not have business logic in it; models should only be for storing or passing data. Design your models to represent the exact structure of the data as it will be presented in the app. When loading a part of the app that needs a specific type of data, use a service method to retrieve all the data asynchronously and then create or update an instance of your model (or models) using the retrieve data. You will need to implement some way for your UI to indicate it is loading data in the meantime, such as by hiding some controls and replacing them with a spinner.

Ideally if you have proper separation of concerns, your code might look something like this:


// Model

public class AccountDetails
{
  public string AccountNumber { get; set; }
  public string AccountName { get; set; }
  public string Balance { get; set; }

  // ...
}

// Service

public class AccountService
{
  public async Task<AccountDetails> GetAccountDetails(string accountNumber)
  {
    using var client = new HttpClient();
    var url = Constant.GetAccountBalanceUrl + accountNumber;
    var response = await client.GetAsync(url);

    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    var model = JsonConvert.DeserializeObject<AccountDetails>(json);
    
    model.Balance = await GetAccountBalance(accountNumber);

    return model;
  }

  public async Task<string> GetAccountBalance(string accountNumber)
  {
    // similar approach as above to get the account balance, as it sounds like it
    // may come from a different source based on your question
  }
}

Then whenever you need to load your model, you simply call the GetAccountDetails method with whatever info is needed (I assumed accountNumber for this example) and await the task it returns. The result of awaiting that task will contain the model with the balance stored in the Balance property, assuming I understand your question correctly.

0
DevLayi On

So, after looking at the problem over and over again, I decided to try andrew's idea by awaiting the first task, get a successResponse, then await the second task, on success, insert the balance into the collection. So, here is what my ViewModel Looks like after the process...

        private async void LoadMyAccounts()
    {
        IsBusy = true;
        HttpClient client = new HttpClient();
        var url = Constant.GetLinkedAccountsUrl;
        var response = await client.GetAsync(url);

        var json = await response.Content.ReadAsStringAsync();

        Account userAccounts = JsonConvert.DeserializeObject<Account>(json);

        List<MyAccount> sorted = userAccounts.Accounts;
        //getTrans = userTransactions
        var allAccounts = new ObservableCollection<MyAccount>(sorted);
        AccountsData = allAccounts;
        acctCounts = AccountsData.Count;

        //List<MyAccount> BalanceArray = new List<MyAccount>();

        foreach (var acct in userAccounts.Accounts)
        {
            string newAcctNo = acct.Details.AccountNumber;

            HttpClient clientee = new HttpClient();
            var urlee = Constant.GetAcctBalanceUrl + newAcctNo;
            var responseee = await clientee.GetAsync(urlee);

            responseee.EnsureSuccessStatusCode();

            var jsonee = await responseee.Content.ReadAsStringAsync();
            var model = JsonConvert.DeserializeObject<AcctModel>(jsonee);
            
            MyAccount ball = model.Balances;

            acct.accountBalance = ball.accountBalance;
            //AccountsData.Add(ball);

        }




        IsBusy = false;


    }