我有这种异步方法:
public async Task<RES> PostAsync<RES>(string url, string content) where RES : new()
{
using (var client = new HttpClient())
{
HttpResponseMessage message = await client.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json"));
var readAsStringAsync = await message.Content.ReadAsStringAsync();
return await readAsStringAsync.FromJsonAsync<RES>(mySerializerSettings);
}
}
将FromJsonAsync
作为扩展方法实施的地方:
public async static Task<T> FromJsonAsync<T>(this string data, JsonSerializerSettings settings) where T : new()
{
return (T)(await JsonConvert.DeserializeObjectAsync<T>(data, settings));
}
现在我想添加一个常规的同步Post
方法,我认为实现将是:
public RES Post<RES>(string url, string content) where RES : new()
{
return PostAsync<RES>(url, content).Result;
}
但并不确实有效。我看到请求是通过Http嗅探器发送的,我收到了回复,但是在调试时我遇到了问题,无法继续。
顺便说一句,确实工作(使用Result
代替await
):
public RES Post<RES>(string url, string content) where RES : new()
{
using (var client = new HttpClient())
{
HttpResponseMessage message = client.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json")).Result;
var readAsStringAsync = message.Content.ReadAsStringAsync().Result;
return readAsStringAsync.FromJson<RES>(mySerializerSettings);
}
}
将FromJson
作为扩展方法实施的地方:
public static T FromJson<T>(this string data, JsonSerializerSettings settings) where T : new()
{
return (T)JsonConvert.DeserializeObject<T>(data, settings);
}
该应用程序是一个Web后端(WebApi)。
我做错了什么?
答案 0 :(得分:2)
你手上可能有僵局。
Asp.net使用SynchronizationContext
将延续发布回请求上下文。如果上下文被阻止(就像在PostAsync<RES>(url, content).Result
上那样),则无法执行继续,因此异步方法无法完成,并且您有死锁。
您可以使用ConfigureAwait(false)
:
public async Task<RES> PostAsync<RES>(string url, string content) where RES : new()
{
using (var client = new HttpClient())
{
HttpResponseMessage message = await client.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json"));
var readAsStringAsync = await message.Content.ReadAsStringAsync().ConfigureAwait(false);
return await readAsStringAsync.FromJsonAsync<RES>(mySerializerSettings).ConfigureAwait(false);
}
}
但最好还是避免同步阻止异步代码开始,并为同步和异步提供两个不同的版本。
答案 1 :(得分:2)
虽然可能,但我不会使用@ i3arnon提供的答案。通常,您不应该阻止异步代码。尽管<script>
var data=[
<?php
$connection =mysql_connect("localhost","root","") or die ("we couldn't connect!");
mysql_select_db("testdatabase");
$query = mysql_query("CREATE OR REPLACE VIEW view1 AS SELECT value FROM testtable") or die(mysql_error());
$r2 = mysql_query("SELECT SUM(value) as value FROM view1;") or die(mysql_error());
while($row = mysql_fetch_array($r2))
{
echo $row['value'].',';
}
?>];
window.alert(data);
</script>
确实有用,但它可能会导致您的代码库出现混淆,而其他开发人员也可能最终使用ConfigureAwait(false)
进行阻止,而不使用.Result
或了解其含义。
相反,公开真正同步的同步方法:
ConfigureAwait
答案 2 :(得分:0)
您似乎有一个非异步功能,并且您想要启动一个将调用PostAsync并等待此任务完成并返回任务结果的任务。这是你的问题吗?
您的代码可能是:
public async Task<RES> PostAsync<RES>(string url, string content) where RES : new()
{
// start the task that will call PostAsync:
var postTask = Task.Run( () => PostAsync(url, content));
// while this task is running you can do other things
// once you need the result: wait for the task to finish:
postTask.Wait();
// If needed check Task.IsFaulted / Task.IsCanceled etc. to check for errors
// the returned value is in Task.Result:
return postTask.Result;
}