0

I created a Xamarin Forms app that used SQLite for the device database. I was able to make calls such as string name = GetItemByID(1).Result.item_name. This worked wonderfully, good performance and returned my data.

I have since converted my project to using Azure Mobile Apps with a node.js backend and WindowsAzure.MobileServices / MobileServices.SQLiteStore. Now, the exact same call in the exact same application never finishes. I have followed all of the Get Started tutorials for Azure Mobile Apps/App Services and the TodoAzure and other Todo tutorials.

On methods/objects where I don't need a specific row/column, I can retrieve data using the standard async Task await process. However, I have some settings that I need to pull from the database that require me to pull just a single row and a single column, synchronously. The app cannot proceed without this value so it must wait until this value is retrieved from the database. I can't seem to get this to work. It seems that the MobileServices requires all of the data retrieval to use async Tasks and everything I have tried has failed.

So what is the SQLite equivalent for the Task.Result.? Can I use SQLite alongside of (or instead of) MobileServices since SQLite just seems to work better? If so, any links or examples or tutorials would be very welcome.

SQLite call & method that works:

    strAppID = GetApplicationInfoByName("App").Result.id;

    public Task<ApplicationInfo> GetApplicationInfoByName(string name)
    {
        return sqlConn.Table<ApplicationInfo>().Where(t => t.name == name).FirstOrDefaultAsync();
    }

MobileServices call & method that does not work. It simply hangs (I'm sure due to a blocking thread?)

    strAppID = GetApplicationInfoByName("App").Result.id;

    public async Task<ApplicationInfo> GetApplicationInfoByName(string name)
    {
        IEnumerable<ApplicationInfo> items = await appInfoTable
                .Where(t => t.name == name)
                .ToEnumerableAsync();

        return items.FirstOrDefault();
    }
Stacy
  • 307
  • 2
  • 8

2 Answers2

0

Sounds like you are not understanding the Task async/await structure. There is not reason why you can't wait for the result to be available.

public async Task<AppInfo> GetAppInfoByName(string name) 
{
    return await appInfoTable.Where(t => t.name == name).FirstOrDefault();
}

... should do the trick. note the async keyword on the GetAppInfoByName() definition. That works hand in hand with await.

Adrian Hall
  • 7,990
  • 1
  • 18
  • 26
  • I am using the "await" keyword in my example above where it says "items = await appInfoTable" so I believe I was using it properly. I did re-write my method to match your example but I get the error that IMobileServiceTableQuery' does not contain a definition for 'FirstOrDefault()'. So I changed your 'FirstOrDefault()' to be 'ToListAsync()'. It still hangs. When I pause the execution and view waiting tasks, I can see that this task has a status of "Awaiting" but it just never completes. – Stacy Mar 20 '17 at 11:38
  • There is something different here. I've got practically the same code in my app and it works fine. It's starting to look like an initialization code thing. How are you initializing the client and/or table? – Adrian Hall Mar 20 '17 at 23:53
  • I am using the same code as is used in the TodoAzure TodoItemManager.cs file (found at [link](https://github.com/xamarin/xamarin-forms-samples/blob/master/WebServices/TodoAzure/TodoAzure/TodoItemManager.cs)) Thanks to [this post](http://stackoverflow.com/questions/28110681/async-task-never-ends-in-simple-api-client-deadlock) and [this post](http://stackoverflow.com/questions/19335451/async-and-await-are-not-working) I was able to get it working. I'll post my changed code as an answer because the comments don't give me enough characters :). – Stacy Mar 21 '17 at 11:52
0

Thanks to @i3amon's answer on this post, I understand now why it wasn't working. Using the ".Result" was blocking an asynchronous operation. Basically, I was trying to do a "sync over async".

Thanks to @MichaC on this post, I was able to modify my code as per the following to use Task.Run(() => Method()).Wait();

Instead of:

    strAppID = GetApplicationInfoByName("App").Result.id;

I now use the below:

    var app = new ApplicationInfo();
    var taskAppID = Task.Run(async () => { app = await GetApplicationInfoByName("App"); }
    taskAppID.Wait();
    strAppID = app.id;

If the above is not correct or if anyone has a better method, please let me know!

Community
  • 1
  • 1
Stacy
  • 307
  • 2
  • 8