Xamarin Async метод не работает, перемещая его в свой собственный класс

Я пытаюсь очистить свой код и поместить вещи в классы (что-то, что я должен был сделать с самого начала, я знаю). Но я сталкиваюсь с проблемой с asyncTask,

У меня есть следующее async Метод, который изначально находился в том же классе, что и вызов этого метода, т.е. не нужно создавать экземпляры, я просто вызвал метод, он работал асинхронно, и все работало нормально.

Тем не менее, я теперь перенес это async метод нового класса, где я собираюсь разместить все методы, относящиеся к базе данных. Итак, теперь я создаю экземпляр нового класса и вызываю метод, но он, кажется, зависает и никуда не денется.

Вот новый класс с методом asnyc:

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");

        }

    }
}

Вот инстанцирование и вызов метода:

ParseDBQuery myQuery = new ParseDBQuery ();
Task myTask = myQuery.getUserCoupons ();
//myTask.Wait ();

Здесь вы можете увидеть, что я попробовал Wait() метод, и это где он останавливается. Если я удалю Wait() метод, код продолжается до получения значений из async метод (очевидно, из-за await). Проблема, кажется, в новом классе, где метод теперь живет. Если я поставлю точку останова на один из запросов, таких как

DBcompanyName = couponObject.Get<string>("entityName");

... это никогда не достигнет точки останова. Так что проблема где-то здесь, но я не знаю почему.

Странно, если я просто помещу весь метод обратно в тот же класс, что и вызов метода, без создания экземпляра, он работает отлично! Есть идеи?

1 ответ

Это общая тупиковая ситуация, которую я описываю в своем блоге.

Когда async метод ожидает задачу, по умолчанию await будет захватывать "текущий контекст" и использовать его для возобновления async метод. В этом случае этот контекст является контекстом пользовательского интерфейса, который связан с одним потоком пользовательского интерфейса. Когда ваш код блокирует задачу (вызывая Wait), он блокирует поток пользовательского интерфейса. Когда FindAsync задача завершена, asyncgetUserCoupons метод пытается возобновить работу в потоке пользовательского интерфейса, но не может этого сделать, потому что поток пользовательского интерфейса заблокирован.

Кроме того, он работает, когда код находится в классе Main (когда ваш код предположительно вызывается Wait на задание вернулось из FindAsync) так как FindAsync не возобновляется в захваченном контексте.

Идеальным решением является использование await вместо Wait, Это означает, что вызов метода getUserCoupons должен стать asyncи его вызывающий должен использовать await и стать asyncи тд и тп. Это рост async совершенно естественно и должно быть принято. В идеале вы хотите идти "асинхронно до конца"; Я опишу эту концепцию больше в статье MSDN.

Другие вопросы по тегам