我已经和这件事斗争了好几天了,我不知道为什么它是这样的。我希望你们中的一个能给我解释一下。
以下是有关的守则:
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();
}所做的就是在URL上输入一个HEAD请求并获取特定的标头结果。
这里的问题是大约50%的时间它死锁(暂停60秒左右,然后抛出一个TaskCanceledException),其余的50%,它的工作出色。现在,我添加了网络日志记录,这就是死锁发生的情况:
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那么,看起来HttpClient()对象正在被释放吗?但是怎么做呢?为了验证是否存在这种情况,我将代码更改为:
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();
}但它还是死死的。
为什么会发生这种事,有什么解释吗?我认为异步/等待基本上是“暂停”例程,所以无论如何,HttpClient都不应该释放。
还是我完全错过了这条船,这是另一回事。
这里是一个例外的尖叫声:

ETA:,我想展示一下我是如何称呼它的是很重要的。这是一个使用的WPF应用程序。在主视图模型中,我这样称呼它:
public MainViewModel(IDataService ds)
{
_dataService = ds;
this.Initialize();
}
private async void Initialize()
{
var det = await RemoteFileUtils.GetRemoteFileDetailsAsync("https://example.com/file.txt");
}发布于 2017-05-18 15:04:25
这个问题源于它是如何被调用的。
不要在调用类的构造函数中调用它。也要避免async void,除非它在事件处理程序中。
public class MainViewModel : ViewModelBase {
public MainViewModel(IDataService ds) {
_dataService = ds;
this.Initialize += OnInitialize;
//Un-comment if you want to call event immediately
//Initialize(this, EventArgs.Empty);
}
public event EventHandler Initialize;
private async void OnInitialize(object sender, EventArgs e) {
var det = await RemoteFileUtils.GetRemoteFileDetailsAsync("https://example.com/file.txt");
}
//Or call this after class has created.
public void Ready() {
Initialize(this, EventArgs.Empty);
}
}接下来,不要在每次需要发出请求时创建和解析一个新的HttpClient。创建一个实例并在整个应用程序的生命周期中使用该实例。
GetRemoteFileDetailsAsync也应该重构为一个可注入的服务,而不是静态访问。
https://stackoverflow.com/questions/44050189
复制相似问题