Как обрабатывать исключения из StorageFile::OpenAsync, когда URI плохой

У меня есть раздел кода, который правильно загружает изображения из http URI, когда URI действительны, но я не могу понять, как перехватить исключение, которое выдает OpenAsync, когда URI недопустим (приводит к 404).

Проблема в том, что при выходе из лямбды, содержащей вызов OpenAsync, выдается исключение; исключение не выдается в блоке try/catch.

Вопрос в том:

Как правильно перехватить исключение, генерируемое 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
}

2 ответа

У меня был этот вопрос 3 года спустя. Я ссылался на эту статью. Мой сценарий был решен следующим образом:

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

Эта цепочка асинхронных задач может потерпеть неудачу в GetFileFromApplicationUriAsync или в ReadTextAsync бросить исключение. Ключ в том, что при броске единственного соответствия then(...) прототип является последним. При входе в try блок, task::get повторно выдает исключение, пойманное классами параллелизма от вашего имени.

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

Скорее всего, исключение выдается в этой строке, поскольку для возможности передачи StorageFile лямбда-выражению.then выполняет неявное get() для задачи. Вы используете то, что называется "продолжением значения", в то время как вы, вероятно, хотите "продолжение задачи" и проверяете там исключения.

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
    }
 });
Другие вопросы по тегам