Reputation: 543
I am trying to clean up my code and put things in classes (something I should have done from the start, I know). But I am running into a problem with an async
Task
.
I have the following async
method, which was originally in the same class as the call to that method, i.e no instantiation needed, I just called the method, it ran asynchronously, and all worked fine.
However, I have now moved this async
method to a new class, where I intend to put all methods relating to the database. So, now I create an instance of the new class and call the method, but it seems to get hung up and not go anywhere.
Here is the new class with the asnyc method:
public class ParseDBQuery
{
public string DBcompanyName { get; set; }
public string DBofferTitle { get; set; }
public string DBlatitude { get; set; }
public string DBlongitude { get; set; }
public string DBofferDescription { get; set; }
public string DBlogoURL { get; set; }
public async Task getUserCoupons()
{
try{
var query = ParseObject.GetQuery("userCoupons").WhereEqualTo("userObjectID", ParseUser.CurrentUser).Include("couponsObjectID");
IEnumerable<ParseObject> MyResults = await query.FindAsync();
foreach (var result in MyResults)
{
var couponObject = result.Get<ParseObject>("couponsObjectID");
DBcompanyName = couponObject.Get<string>("entityName");
Console.WriteLine ("The company name is......... " + DBcompanyName);
DBofferTitle = couponObject.Get<string>("offerTitle");
Console.WriteLine ("The offer title is......... " + DBofferTitle);
DBofferDescription = couponObject.Get<string>("offerDescription");
Console.WriteLine ("The offer title is......... " + DBofferDescription);
DBlogoURL = couponObject.Get<string>("logoURL");
Console.WriteLine ("The logo URL is......... " + DBlogoURL);
DBlatitude = couponObject.Get<string>("latitude");
Console.WriteLine ("The latitude is......... " + DBlatitude);
DBlongitude = couponObject.Get<string>("longitude");
Console.WriteLine ("The longitude is......... " + DBlongitude);
}
}
catch (ParseException e) {
Console.WriteLine ("There was a problem fetching getUserCoupon data from parse - ParseDBQuery class");
}
}
}
Here is the instantiation and call to the method:
ParseDBQuery myQuery = new ParseDBQuery ();
Task myTask = myQuery.getUserCoupons ();
//myTask.Wait ();
Here you can see i've tried the Wait()
method, and this is where it stops. If i remove the Wait()
method, the code carries on before getting values from the async
method (obviously because of await
). The problem seems to be in the new class where the method now lives. If I put a breakpoint on one of the queries such as
DBcompanyName = couponObject.Get<string>("entityName");
... it never hits the breakpoint. So the problem lies here somewhere but I don't know why.
The odd thing is, if i just put the whole method back into the same class as the method call, without instantiation, it works perfectly! Any ideas?
Upvotes: 0
Views: 925
Reputation: 457382
This is the common deadlock situation that I describe on my blog.
When an async
method awaits a task, by default the await
will capture a "current context" and use that to resume the async
method. In this case, that context is the UI context, which is associated with a single UI thread. When your code blocks on the task (by calling Wait
), it is blocking the UI thread. When the FindAsync
task completes, the async
getUserCoupons
method attempts to resume on the UI thread, but it can't because the UI thread is blocked.
As an aside, it works when the code is in the Main class (when your code presumably called Wait
on the task returned from FindAsync
) because FindAsync
doesn't resume on the captured context.
The ideal solution is to use await
instead of Wait
. This means that the method calling getUserCoupons
must become async
, and its caller should use await
and become async
, etc., etc. This growth of async
is perfectly natural and should be embraced. Ideally, you want to go "async all the way"; I describe this concept more in an MSDN article.
Upvotes: 1