2013-04-03 3 views
0

Я работаю над приложением Windows Store (C++). Это метод, который читается из базы данных с помощью веб-службы.Цепочка завершения функции async для другого

task<std::wstring> Ternet::GetFromDB(cancellation_token cancellationToken) 
{ 
    uriString = ref new String(L"http://myHost:1234/RestServiceImpl.svc/attempt"); 
    auto uri = ref new Windows::Foundation::Uri(Helpers::Trim(uriString)); 
    cancellationTokenSource = cancellation_token_source(); 
    return httpRequest.GetAsync(uri, cancellationTokenSource.get_token()).then([this](task<std::wstring> response)->std::wstring 
    { 
     try 
     { 
      Windows::UI::Popups::MessageDialog wMsg(ref new String(response.get().c_str()), "success"); 
      wMsg.ShowAsync(); 
      return response.get(); 
     } 
     catch (const task_canceled&) 
     { 
      Windows::UI::Popups::MessageDialog wMsg("Couldn't load content. Check internet connectivity.", "Error"); 
      wMsg.ShowAsync(); 
      std::wstring abc; 
      return abc; 
     } 
     catch (Exception^ ex) 
     { 
      Windows::UI::Popups::MessageDialog wMsg("Couldn't load content. Check internet connectivity.", "Error"); 
      wMsg.ShowAsync(); 
      std::wstring abc; 
      return abc; 
     } 
    } , task_continuation_context::use_current()); 
} 

Я смущен, как вернуть полученные данные вызывающей функции. Теперь я называю эту функцию в конструкторе моего класса данных, как это:

ternet.GetFromDB(cancellationTokenSource.get_token()).then([this](task<std::wstring> response) 
{ 
    data = ref new String(response.get().c_str()); 
}); 

Я получаю COM исключение всякий раз, когда я пытаюсь получить возвращаемые данные из GetFromDB(). Но это один работает нормально:

ternet.GetFromDB(cancellationTokenSource.get_token()); 

Пожалуйста, предложите лучший способ сцепления завершения GetFromDB с другим кодом. И как получить возвращаемое значение из блока try {} GetFromDB(). Пожалуйста, имейте в виду, что я очень новый ученик асинхронного программирования.

+0

Опять же, реальный код ошибки исключения был бы полезен. –

+0

Вы можете обернуть вызов .get() в 'try {/*...*/} catch (Platform :: Exception^e) { Платформа :: String^s = e-> Сообщение; }, а затем установить контрольную точку и проверить «s», чтобы получить дополнительную информацию об исключении. –

ответ

0

Если продолжение вызова GetFromDB происходит в потоке пользовательского интерфейса (который я считаю, что это будет по умолчанию, при условии сайта вызова вы вставили происходит в потоке пользовательского интерфейса), то вызов get() на возвращенном task выбросит исключение. Это не позволит вам блокировать поток пользовательского интерфейса, ожидая завершения задачи.

Два предложения, каждое из которых должно исправить эту проблему. Первый должен работать независимо, а второй - только хороший вариант, если вы не пытаетесь получить строку ответа в потоке пользовательского интерфейса (для отображения, например).

1) Напишите ваши продолжения (lambdas, которые вы переходите на then), чтобы они принимали фактический результат предыдущей задачи, а не предыдущую задачу. Другими словами, вместо того, чтобы писать это:

ternet.GetFromDB(...).then([this](task<std::wstring> response) { ... }); 

пишут это:

ternet.GetFromDB(...).then([this](std::wstring response) { ... }); 

Отличие последнего в том, что продолжение техника будет вызывать get() для вас (на фоне потока), а затем дать результат к вашей функции продолжения, которая намного проще. Вам нужно только, чтобы ваше продолжение принимало фактическую задачу в качестве аргумента, если вы хотите поймать исключения, которые могли быть выбраны заданием по мере ее выполнения.

2) Скажите это запустить продолжение на фоне/произвольной резьбы:

ternet.GetFromDB(...).then([this](task<std::wstring> response) { ... }, task_continuation_context::use_arbitrary()); 

Он не будет заботиться, если вы будете блокировать фоновый поток, он только заботится, если вы звоните get() в потоке пользовательского интерфейса.