TransWikia.com

WebRequest.GetResponseAsync throws uncatchable exception

Stack Overflow Asked by Blaise on December 29, 2020

Writing a small Xamarin Forms Android app in VS 2019. I have a simple async routine that checks for the existence of a file on a web server. This routine is called 3 times in a loop to try to overcome any transient network problems that may be encountered.

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;

}

Note 1: BoolResult is a simple struct that has a bool and a string, so the caller can distinguish between a "file not found" exception (which may be expected) and any other "real" exceptions. The caller breaks out of its loop if the result is FNF.

Note 2: My test for "file not found" is admittedly crude; I simply did not see a way to determine same through a status code or what have you. I’d appreciate any guidance on a better way to determine FNF.

The routine generally works fine. But when debugging on an Android phone that has both wireless and mobile data turned off (to simulate a network problem), the routine works as expected the first time it’s run (a "NameResolutionFailure" exception is caught on the call to req.GetResponseAsync).

But on the second time through, the app crashes on that statement (req.GetResponseAsync), with the following debug output:

11-01 08:25:11.579 F/ ( 9983): * Assertion at
/Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mono/mini/debugger-agent.c:4660,
condition is_ok (error)' not met, function:get_this_async_id, Could not execute the method because the containing type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder1[T_REF]’, is
not fully instantiated. assembly: type: member:(null) 11-01 08:25:11.580 F/libc ( 9983): Fatal signal
6 (SIGABRT), code -1 (SI_QUEUE) in tid 10061 (Thread Pool Wor), pid
9983 (oft.cryptovault)

[note: cryptovault (last word of the debug output) is the name of the app]

I’m at a a loss here – I have no idea why this happens or what I can do about it; any advice would be appreciated.

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

20201105 update: I tried using HttpClient instead of WebRequest, per suggestion from @Leo Zhu – MSFT. Modified code follows.

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

Pretty much the same result: first time through I get a "No such host is known" exception (as expected), and the second time I get a crash on the line:

response = await client.SendAsync(request)

Got the following debug log output:

11-05 10:46:51.370 F/ (14819): * Assertion at
/Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mono/mini/debugger-agent.c:4568,
condition `array->len == 1′ not met 11-05 10:46:51.370 F/libc
(14819): Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 14869
(Thread Pool Wor), pid 14819 (oft.cryptovault)

To see if I get a crash when running the routine a second time after the first time succeeds, I turned on Mobile data and forced a failure on the first time through (by setting ret.Result=false, even though the client.SendAsync call succeeded), and found no problem the second time through.

I am certainly puzzled … thoughts anyone?

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP