C# HttpClient等待SendAsync死锁
我已经为此奋斗了好几天,但我不明白为什么会这样。我希望你们中的一位策划人能向我解释一下 以下是相关代码:C# HttpClient等待SendAsync死锁,c#,http,asynchronous,async-await,C#,Http,Asynchronous,Async Await,我已经为此奋斗了好几天,但我不明白为什么会这样。我希望你们中的一位策划人能向我解释一下 以下是相关代码: public async static Task<RemoteFileDetails> GetRemoteFileDetailsAsync(string strUrl, double dblTimeoutSeconds = 15.0) { try { using (var hc = new HttpClient()) {
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();
}
看来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();
}
问题源于如何调用它 不要在调用类的构造函数中调用它。也要避免
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
。创建一个实例,并在应用程序的整个生命周期中使用它
getRemoteFileDetailsSync
也应该重构为可注入服务,而不是静态访问。您是否尝试过。配置等待(continueOnCapturedContext:false)
?我想知道您是否直接从UI线程调用此函数。@xxbbcc是的,它不会改变任何东西。昨天就试过了。我将更新问题以显示我如何调用它。@xxbbcc好的,我更新了问题以显示我如何调用它。@Sonic:因为调用这个。初始化();未等待,可能会导致死锁。这篇文章可能会有所帮助。我不认为这是被处置;请求正在被取消,这听起来像是一个代理配置错误。一个问题:你说每个应用程序应该只有一个HttpClient。我可以同时在多个线程之间使用HttpClient对象吗?或者我必须将HttpClient以独占方式锁定到线程,直到HTTP传输完成?@Sonic检查答案中的链接。不需要锁定客户端。还有一个问题。在上面的例子中,如果您想立即调用event,您会说//uncomment,但如果我这样做了,我不是回到了我调用异步void
方法的同一条船上,而没有使用wait?@Sonic调用事件处理程序,这一次允许异步void。当你有时间阅读斯蒂芬的这篇文章时Cleary@Sonic刚刚意识到我的错误。假设您引发事件,该事件将调用事件处理程序。
public MainViewModel(IDataService ds)
{
_dataService = ds;
this.Initialize();
}
private async void Initialize()
{
var det = await RemoteFileUtils.GetRemoteFileDetailsAsync("https://example.com/file.txt");
}
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);
}
}