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:
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");
}