Esoo Keca
Esoo Keca

Reputation: 13

How to handle exceptions from StorageFile::OpenAsync when URI is bad

I have a section of code that correctly load images from http URIs when the URIs are valid but I cannot figure how to catch the exception OpenAsync throws when the URI is invalid (results in 404).

The problem is that when the lambda which contains the call to OpenAsync exits, the exception is thrown; the exception is not thrown while in the try/catch block.

The question is:

What is the correct way to catch the exception thrown by StorageFile::OpenAsync?

auto bm = ref new BitmapImage();
try {
    Uri^ uri = ref new Uri("http://invaliduri.tumblr.com/avatar/128");

    auto task = Concurrency::create_task(CreateStreamedFileFromUriAsync("temp-web-file.png", uri, nullptr));

    task.then([] (StorageFile^ file) {
        try {
            return file->OpenAsync(FileAccessMode::Read);
        } catch (...) {
            // this does not catch the exception because the exception
            //   occurs after this lambda is exitted
        }
    }).then([bm](IRandomAccessStream^ inputStream) {
        try {
            return bm->SetSourceAsync(inputStream);
        } catch (...) {
            // this does not catch the exception because the exception
            //   occurs before this lambda is entered
        }
    });
} catch (...) {
    // and obviously this would not catch the exception
}

Upvotes: 1

Views: 1465

Answers (2)

Cpp Num Nums
Cpp Num Nums

Reputation: 21

I had this question 3 years later. I referenced this article. My scenario was, then, solved as follows,

#include<ppltasks.h>
...
auto file = ref new Windows::Foundation::Uri::Uri("ms-appx:///SomeFile.txt");
concurrency::create_task(Windows::Storage::StorageFile::GetFileFromApplicationUriAsync(data))
.then([](Windows::Storage::StorageFile^ f) {
    return Windows::Storage::FileIO::ReadTextAsync(f);
})
.then([this](String^ s) {
    this->someFileContent = s;
})
.then([](concurrency::task<void> t) {
    try {
        t.get();
    } catch(Platform::COMException^ e) {
        OutputDebugString(e->Message->Data());
    }
});

This async task chain may fail in GetFileFromApplicationUriAsync or in ReadTextAsync throwing an exception. The key is that when thrown the only matching then(...) prototype is the final one. On entering the try block, task::get re-throws the exception caught by the concurrency classes on your behalf.

Upvotes: 2

Metro101
Metro101

Reputation: 188

task.then([] (StorageFile^ file) {  // this is where the exception is actually thrown

The exception is most likely thrown on this line because to be able to pass in the StorageFile to the lambda the .then is doing a non-explicit get() on the task. You're using what is called a "value continuation" while you probably want a "task continuation" and check for exceptions there.

auto task = Concurrency::create_task(CreateStreamedFileFromUriAsync("temp-web-file.png", uri, nullptr));

task.then([] (concurrency::task<StorageFile^> fileTask) {

    StorageFile^ file;

    try 
    {
        file = fileTask.get(); // this is what actually throws if Uri is wrong

        create_task(file->OpenAsync(FileAccessMode::Read)).then(/* ... */);

    } catch (...) 
    {
        // nothing to do here
    }
 });

Upvotes: 1

Related Questions