Как перехватить ВСЕ исключения в асинхронном вызове HttpClient? - PullRequest
0 голосов
/ 21 сентября 2019

У меня есть следующая функция, которая загружает веб-страницу:

    static bool myFunction(int nmsTimeout, out string strOutErrDesc)
    {
        //'nmsTimeout' = timeout in ms for connection
        //'strOutErrDesc' = receives error description as string
        bool bRes = false;
        strOutErrDesc = "";

        HttpClient httpClient = null;
        System.Threading.Tasks.Task<string> tsk = null;

        try
        {
            httpClient = new HttpClient();
            tsk = httpClient.GetStringAsync("https://website-to-connet.com");

            if (tsk.Wait(nmsTimeout))
            {
                if (tsk.Status == System.Threading.Tasks.TaskStatus.RanToCompletion)
                {
                    string strRes = tsk.Result;
                    strRes = strRes.Trim();

                    if (!string.IsNullOrWhiteSpace(strRes))
                    {
                        bRes = true;
                    }
                    else
                    {
                        //Empty result
                        strOutErrDesc = "Empty result";
                    }
                }
                else
                {
                    //Bad task completion
                    strOutErrDesc = "Bad completion result: " + tsk.Status.ToString();
                }
            }
            else
            {
                //Timed out
                strOutErrDesc = "Timeout expired: " + nmsTimeout + " ms.";
            }
        }
        catch (Exception ex)
        {
            //Error
            strOutErrDesc = "Exception: " + ex.Message;
            if (tsk != null)
            {
                strOutErrDesc += " -- ";
                int c = 1;
                foreach(var exc in tsk.Exception.InnerExceptions)
                {
                    strOutErrDesc += c.ToString() + ". " + exc.InnerException.Message;
                }
            }

            bRes = false;
        }

        return bRes;
    }

Я подумал, что моей конструкции try / catch достаточно, чтобы перехватить все исключения в ней.

До тех пор, пока я не обнаружил следующее исключение и сообщение об ошибке Windows, из-за которого произошло сбой приложения:

enter image description here

Необработанное исключение: System.AggregateException: исключение задачине было обнаружено ни Ожидание задания, ни доступ к его свойству Исключение.В результате ненаблюдаемое исключение было переброшено потоком финализатора.---> System.Net.Http.HttpRequestException: код состояния ответа не указывает на успешность: 503 (служба недоступна).

--- Конец трассировки стека внутренних исключений ---

в System.Threading.Tasks.TaskExceptionHolder.Finalize ()

Что это такое и как мне его поймать?

Ответы [ 2 ]

0 голосов
/ 21 сентября 2019

Обратите внимание, что то, что описано здесь, является старым поведением (как указано в комментариях), и оно не происходит с .NET 4.5 и новее.

Что происходит, так это то, что Задача не была успешно завершена иВы не проверяете ошибки.Когда сборщик мусора пытается очистить объект Task, он находит там необработанное исключение и выбрасывает его в AggregateException.Это исключение, которое фактически не выбрасывается в ваш блок try (он даже находится в другом потоке), поэтому ваш улов не может его перехватить.

То, что вы хотите сделать, это правильно await созданная задача.Возможно, вы захотите прочитать об асинхронном / ожидании в C # на этом этапе.Если вы хотите, чтобы задание можно было отменить, вам, возможно, придется использовать GetAsync с токеном отмены, или вам придется ждать, пока GetStringAsync не завершится в какой-то момент.

Если вы по какой-то причине неЕсли вы хотите использовать асинхронный способ ожидания (вы должны!), вы все равно можете использовать tsk.Wait();.Это, однако, обернет выброшенное исключение в AggregateException, и вызов будет синхронным .

И если вы действительно не можете оставаться рядом и ждать завершения своей функции, вы можете увидеть в этот вопрос , как автоматически обрабатывать проверку исключений с помощью задачи продолжения.

Однако я бы очень посоветовал вам использовать async / await и правильно проверить, как завершаются задачи и что они выдают.

0 голосов
/ 21 сентября 2019

Приложение упало, потому что try / catch - это не хак "везде поймай", оно только перехватывает исключения, которые генерируются в том же стеке вызовов или в том же контексте вызова.

Вы, с другой стороныпо какой-то причине используйте синхронный метод для запуска асинхронных задач, они выполняются в других потоках, и контекст для них теряется.

Либо используйте синхронизирующие версии этих методов, либо, что еще лучше, используйте асинхронный метод и await в ваших асинхронных задачах, это сохранит контекст вызова и позволит вам перехватить любое исключение, выброшенное изнутри, с помощью блока try / catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...