I'm having an issue with my Xamarin Android app, but I believe I have narrowed the issue down to the Azure Mobile Client or my lack of understanding of Tasks in .Net. I have attempted to recreate my issue on a console app.
My goal is to make multiple api calls in parallel. In the example below I just make repeated calls to retrieve a user that does exists in the database. When I await each call (GetUsersB method) everything runs fine, but when I try to await Task.WhenAll (GetUsersA method) I almost always get an exception.
class Program
{
static void Main(string[] args)
{
var service = new MyService();
try
{
//GetUsersA(service).Wait(); //Often throws the exception attached but ocasionally is successful
GetUsersB(service).Wait(); //Never throws an exception
}
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
Console.WriteLine(e.InnerException.Message);
Console.WriteLine(e.InnerException.StackTrace);
}
}
Console.WriteLine("main done");
Console.ReadLine();
}
public async static Task GetUsersA(MyService service)
{
await Task.WhenAll(service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"));
Console.WriteLine("tasks complete");
}
public async static Task GetUsersB(MyService service)
{
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
Console.WriteLine("tasks complete");
}
}
if needed here is the MyService class
public class MyService
{
private MobileServiceClient azClient;
public MyService()
{
azClient = new MobileServiceClient("https://mysite.azurewebsites.net/");
}
public async Task<User> GetUser(string id)
{
return await azClient.GetTable<User>().LookupAsync(id);
}
}
Here is the output of the inner exception:
Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
at Microsoft.WindowsAzure.MobileServices.MobileServiceContractResolver.CreateProperties(Type type, MemberSerialization memberSerialization)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
at Microsoft.WindowsAzure.MobileServices.MobileServiceContractResolver.CreateObjectContract(Type type)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.<>c__DisplayClass35_0`1.<Deserialize>b__0()
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.TransformSerializationException[T](Action action, JToken token)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.Deserialize[T](JToken json, JsonSerializer jsonSerializer)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.Deserialize[T](JToken json)
at Microsoft.WindowsAzure.MobileServices.MobileServiceTable`1.<LookupAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.WindowsAzure.MobileServices.MobileServiceTable`1.<LookupAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TaskTest.MyService.<GetUser>d__2.MoveNext() in C:\Users\jalley\Documents\Visual Studio 2015\Projects\TaskTest\TaskTest\MyService.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TaskTest.Program.<GetUsersA>d__1.MoveNext() in C:\Users\jalley\Documents\Visual Studio 2015\Projects\TaskTest\TaskTest\Program.cs:line 31