WebRequest.GetResponseAsync引发无法捕获的异常

时间:2020-11-01 14:20:46

标签: c# android exception xamarin.forms async-await

在VS 2019中编写一个小的Xamarin Forms Android应用程序。我有一个简单的异步例程,用于检查Web服务器上是否存在文件。该例程被循环调用3次,以尝试克服可能遇到的任何瞬时网络问题。

private async Task <BoolResult> CloudFileExistsAsync(string cloudFile, NetworkCredential creds)
{
    DebugPrint("CloudFileExistsAsync(file, creds) entered, for " + cloudFile);

    BoolResult ret = new BoolResult(false);

    WebRequest req = WebRequest.Create(cloudFile);

    req.Timeout = NetworkTimeout;
    req.Method = "HEAD";

    //if we weren't passed creds, create them now
    if (creds == null)
        creds = GetNetworkCreds(false);

    req.Credentials = creds;

    HttpWebResponse response = null;

    try
    {
        response = (HttpWebResponse)(await req.GetResponseAsync());
        ret.Result = true;
    }
    catch (Exception ex)
    {
        if (ex.Message.Contains("(404)"))
        {
            ret.Message = _FNF_Message;
            DebugPrint("'" + cloudFile + "' doesn't exist: " + ex.Message);
        }
        else
        {
            ret.Message = ex.Message;
            DebugLogException(ex, "trying to check exitance of '" + cloudFile + "'");
        }
    }
    finally
    {
        response?.Close();
        response?.Dispose();
    }

    DebugPrint("CloudFileExistsAsync(file, creds) exiting, ret = " + ret);

    return ret;

}

注1:BoolResult是具有bool和字符串的简单结构,因此调用方可以区分“未找到文件”异常(可能是预期的)和任何其他“真实”异常。如果结果是FNF,则调用方将退出循环。

注2:我对“找不到文件”的测试被认为是粗略的;我只是没有看到一种通过状态代码或您所拥有的信息来确定相同内容的方法。感谢您提供有关确定FNF的更好方法的指导。

该例程通常运行良好。但是,当在同时关闭了无线和移动数据的Android手机上进行调试(以模拟网络问题)时,该例程将在首次运行时按预期方式工作(对req.GetResponseAsync的调用中捕获了“ NameResolutionFailure”异常)

但是第二次,应用程序在该语句(req.GetResponseAsync)上崩溃,并显示以下调试输出:

11-01 08:25:11.579 F /(9983):*断言为 /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mono/mini/debugger-agent.c:4660, 条件is_ok (error)' not met, function:get_this_async_id, Could not execute the method because the containing type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder 1 [T_REF]'为 尚未完全实例化。汇编:类型:成员:(null)11-01 08:25:11.580 F / libc(9983):致命信号 6(SIGABRT),代码-1(SI_QUEUE),在TID 10061(线程池Wor)中,PID 9983(oft.cryptovault)

[注意:cryptovault(调试输出的最后一个字)是应用程序的名称]

我在这里不知所措-我不知道为什么会发生这种情况或对此我能做些什么;任何建议将不胜感激。

===================

20201105更新:根据@Leo Zhu-MSFT的建议,我尝试使用HttpClient代替WebRequest。修改后的代码如下。

private async Task<BoolResult> CloudFileExistsHttpClientAsync(string cloudFile, NetworkCredential creds)
{
    DebugPrint("CloudFileExistsHttpClientAsync entered for '" + cloudFile + "'");
    BoolResult ret = new BoolResult(false);

    HttpClientHandler handler = null;
    HttpClient client = null;
    HttpRequestMessage request = null;
    HttpResponseMessage response = null;

    try
    {
        handler = new HttpClientHandler { Credentials = creds };
        client = new HttpClient(handler);
        client.Timeout = new TimeSpan(0, 0, (int)(NetworkTimeout / 1000));
        request = new HttpRequestMessage(HttpMethod.Head, cloudFile);
        response = await client.SendAsync(request);

        DebugPrint("CloudFileExistsHttpClientAsync status code =" + response.StatusCode);

        switch(response.StatusCode)
        {
            case HttpStatusCode.OK:
                ret.Result = true;
                break;

            case HttpStatusCode.NotFound:
                ret.Message = _FNF_Message;
                break;

            default:
                ret.Message = response.StatusCode.ToString();
                break;
        }

    }
    catch (Exception ex)
    {
        DebugLogException(ex, "CloudFileExistsHttpClientAsync trying to check exitance of '" + cloudFile + "'");
        ret.Message = ex.Message;
    }
    finally
    {
        handler?.Dispose();
        client?.Dispose();
        request?.Dispose();
        response?.Dispose();
    }

    DebugPrint("CloudFileExistsHttpClientAsync exiting, ret = " + ret);
    return ret;
}

几乎相同的结果:第一次,出现“未知主机未知”异常(如预期的那样),第二次,我崩溃了:

响应=等待客户端。SendAsync(请求)

获得以下调试日志输出:

11-05 10:46:51.370 F /(14819):*断言 /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mono/mini/debugger-agent.c:4568, 不符合条件'array-> len == 1'11-05 10:46:51.370 F / libc
(14819):在tid 14869中出现致命信号6(SIGABRT),代码-1(SI_QUEUE) (线程池线程数),pid 14819(oft.cryptovault)

要查看第一次成功后第二次运行例程时是否崩溃,我打开了移动数据并强制第一次失败(通过设置ret.Result = false,即使客户端.SendAsync调用成功),并且第二次没有问题。

我当然很困惑……有人在想吗?

0 个答案:

没有答案