HttpClient await SendAsync deadlock

Viewed 1381

I have been battling this for days now and can't figure it out or why it is the way it is. I am hoping one of you masterminds can explain it to me.

This is the code in question:

public async static Task<RemoteFileDetails> GetRemoteFileDetailsAsync(string strUrl, double dblTimeoutSeconds = 15.0)
{
    try
    {
        using (var hc = new HttpClient())
        {
            hc.Timeout = TimeSpan.FromSeconds(dblTimeoutSeconds);
            using (var h = new HttpRequestMessage(HttpMethod.Head, strUrl))
            {
                h.Headers.UserAgent.ParseAdd(UserAgent);
                using (var rm = await hc.SendAsync(h))
                {
                    rm.EnsureSuccessStatusCode();
                    return new RemoteFileDetails()
                    {
                        Url = strUrl,
                        FileName = rm.Content.Headers.ContentDisposition.FileName,
                        FileSize = rm.Content.Headers.ContentLength.GetValueOrDefault(),
                        LastModified = rm.Content.Headers.LastModified.GetValueOrDefault().LocalDateTime,
                        Valid = true
                    };
                }
            }
        }
    }
    catch (Exception ex)
    {
        System.Windows.MessageBox.Show(ex.ToString());
    }
    return new RemoteFileDetails();
}

All this does is puts in a HEAD request on a URL and grabs the certain header results.

The issue here is about 50% of the time it deadlocks (pauses for 60 seconds or so, then throws a TaskCanceledException), the other 50% it works wonderfully. Now, I added network logging, and this is what's happening on deadlock:

    System.Net Verbose: 0 : [2928] HttpWebRequest#3567399::HttpWebRequest(https://www.example.com/file.txt#-114720138)
    System.Net Information: 0 : [2928] Current OS installation type is 'Client'.
    System.Net Information: 0 : [2928] RAS supported: True
    System.Net Verbose: 0 : [2928] Exiting HttpWebRequest#3567399::HttpWebRequest() 
    System.Net Verbose: 0 : [2928] HttpWebRequest#3567399::HttpWebRequest(uri: 'https://www.example.com/file.txt', connectionGroupName: '565144')
    System.Net Verbose: 0 : [2928] Exiting HttpWebRequest#3567399::HttpWebRequest() 
    System.Net Verbose: 0 : [5456] HttpWebRequest#3567399::BeginGetResponse()
    System.Net Verbose: 0 : [2244] HttpWebRequest#3567399::Abort()
    System.Net Error: 0 : [2244] Exception in HttpWebRequest#3567399:: - The request was aborted: The request was canceled..
/////// THIS IS WHERE THE 30-60 SECOND PAUSE HAPPENS ////////
    System.Net Error: 0 : [5456] Can't retrieve proxy settings for Uri 'https://www.example.com/file.txt'. Error code: 12180.
    System.Net Verbose: 0 : [5456] ServicePoint#39086322::ServicePoint(www.example.com:443)
    System.Net Information: 0 : [5456] Associating HttpWebRequest#3567399 with ServicePoint#39086322
    System.Net Verbose: 0 : [2244] Exiting HttpWebRequest#3567399::Abort() 
    System.Net Verbose: 0 : [5456] HttpWebRequest#3567399::EndGetResponse()
    System.Net Error: 0 : [5456] Exception in HttpWebRequest#3567399::EndGetResponse - The request was aborted: The request was canceled..
    System.Net Verbose: 0 : [5456] Exiting HttpWebRequest#3567399::BeginGetResponse()   -> ContextAwareResult#36181605

So, it looks like the HttpClient() object is getting disposed? But how? To verify that this may be the case, I changed the code to this:

private static HttpClient _hc;
public async static Task<RemoteFileDetails> GetRemoteFileDetailsAsync(string strUrl, double dblTimeoutSeconds = 15.0)
{
    _hc = new HttpClient();
    try
    {
        _hc.Timeout = TimeSpan.FromSeconds(dblTimeoutSeconds);
        using (var h = new HttpRequestMessage(HttpMethod.Head, strUrl))
        {
            h.Headers.UserAgent.ParseAdd(UserAgent);
            using (var rm = await _hc.SendAsync(h))
            {
                rm.EnsureSuccessStatusCode();
                return new RemoteFileDetails()
                {
                    Url = strUrl,
                    FileName = rm.Content.Headers.ContentDisposition.FileName,
                    FileSize = rm.Content.Headers.ContentLength.GetValueOrDefault(),
                    LastModified = rm.Content.Headers.LastModified.GetValueOrDefault().LocalDateTime,
                    Valid = true
                };
            }
        }
    }
    catch (Exception ex)
    {
        System.Windows.MessageBox.Show(ex.ToString());
    }
    return new RemoteFileDetails();
}

but it still deadlocks the same.

Is there any explanation is to why this is happening? I thought async/await was basically "pausing" the routine, so the HttpClient should never dispose, anyway.

Or am I missing the boat totally here and it's something else.

Here is a screencap of the exception: enter image description here

ETA: I suppose it's important to show how I am calling this. This is a WPF app using MVVM Light. In the main view model, i am calling this as so:

    public MainViewModel(IDataService ds)
    {
        _dataService = ds;
        this.Initialize();
    }

    private async void Initialize()
    {
        var det = await RemoteFileUtils.GetRemoteFileDetailsAsync("https://example.com/file.txt");
}
1 Answers
Related