当我执行此操作时,它不会返回Task<TokenModel>
我的意思是此行已冻结tokenModel = await response.Content.ReadAsAsync<TokenModel>();
Foo()
{
var r = IsLoginOk();
}
public async Task<TokenModel> IsLoginOk()
{
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
handler.PreAuthenticate = true;
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
client = new HttpClient(handler);
client.BaseAddress = new Uri(Properties.Settings.Default.WebApiUrl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var apiAccountLogin = apiManager.ApiAccountLogin(Properties.Settings.Default.WebApiPassword, Properties.Settings.Default.WebApiUsername);
var response = await client.PostAsJsonAsync(apiAccountLogin.Url, apiAccountLogin.Container);
response.EnsureSuccessStatusCode();
tokenModel = await response.Content.ReadAsAsync<TokenModel>();
return tokenModel;
}
但是如果我使用void
那么它工作正常
Foo()
{
IsLoginOk();
}
public async void IsLoginOk()
{
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
handler.PreAuthenticate = true;
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
client = new HttpClient(handler);
client.BaseAddress = new Uri(Properties.Settings.Default.WebApiUrl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var apiAccountLogin = apiManager.ApiAccountLogin(Properties.Settings.Default.WebApiPassword, Properties.Settings.Default.WebApiUsername);
var response = await client.PostAsJsonAsync(apiAccountLogin.Url, apiAccountLogin.Container);
response.EnsureSuccessStatusCode();
tokenModel = await response.Content.ReadAsAsync<TokenModel>();
}
我看到我的代码就像Microsift示例代码http://msdn.microsoft.com/en-us/library/hh191443.aspx。
这是一种死锁?
我需要返回 tokenModel 。我怎么能这样做? 谢谢!
答案 0 :(得分:3)
像这样更改构造函数:
private Foo()
{
// Do only synchronous initialization here
}
public static async Task<Foo> CreateAsync()
{
var foo = new Foo();
await foo.IsLoginOk();
return foo;
}
您的呼叫方需要相应更改。
答案 1 :(得分:2)
我不确定,但您的代码应该是这样的
这是一种方法
public async void Foo()
{
var r = await IsLoginOk();
}
这样做的方法是在拨打电话时使用ConfigureAwait(false)
,如下所示。
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
对于这种行为,我在Google上搜索并找到了这篇好文章。请阅读以避免将来出现问题:Don't Block on Async Code
如果代码是这样的
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public void Button1_Click(...)
{
var jsonTask = GetJsonAsync(...);
textBox1.Text = jsonTask.Result;
}
它挂起所以这就是发生的事情,从顶级方法开始(Button1_Click for UI):
答案 2 :(得分:1)
您的代码是causing a deadlock that I explain on my blog。简而言之,当await
暂停async
方法时,默认情况下它将捕获上下文(例如,UI上下文或ASP.NET请求上下文)。稍后,当await
完成时,async
方法将在该上下文中恢复。但是,如果调用代码使用Task.Wait
或Task<T>.Result
同步阻止async
方法,则它会阻止该上下文中的线程,并且async
方法无法完成。
正确的解决方案是一直使用async
,而不是使用async void
或ConfigureAwait(false)
:
async Task FooAsync()
{
var result = await IsLoginOkAsync();
}
public async Task<TokenModel> IsLoginOkAsync();
答案 3 :(得分:-1)
IsLoginOk()将返回一个任务。 要单独返回TokenModel,请使用
var r = IsLoginOk().Result;
如果您不等待结果,则执行将继续,因为它是异步的。此外,Name应为IsLoginAsync()