I am working on a Windows Store (C++) app. This is a method that reads from the database using the web service.

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());
}

I'm confused how to return the received data to the calling function. Now, I am calling this function in the constructor of my data class like this:

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

I am getting a COM exception whenever I try to receive the returned data from GetFromDB(). But this one runs fine:

ternet.GetFromDB(cancellationTokenSource.get_token());

Please suggest a better way of chaining the completion of GetFromDB to other code. And how to get the returned value from inside the try{} block of GetFromDB() 's then. Please keep in mind I am a very new student of async programming.

有帮助吗?

解决方案

If the continuation of the call to GetFromDB is happening on the UI thread (which I believe it will by default, assuming the call site you pasted is occurring in the UI thread), then calling get() on the returned task will throw an exception. It won't let you block the UI thread waiting for a task to finish.

Two suggestions, either of which should fix that problem. The first should work regardless, while the second is only a good option if you're not trying to get the response string to the UI thread (to be displayed, for example).

1) Write your continuations (lambdas that you pass to then) so that they take the actual result of the previous task, rather than the previous task itself. In other words, instead of writing this:

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

write this:

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

The difference with the latter is that the continuation machinery will call get() for you (on a background thread) and then give the result to your continuation function, which is a lot easier all around. You only need to have your continuation take the actual task as an argument if you want to catch exceptions that might have been thrown by the task as it executed.

2) Tell it to run your continuation on a background/arbitrary thread:

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

It won't care if you block a background thread, it only cares if you call get() on the UI thread.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top