c# - 通过调用 <asyncmethod>.Result 实现同步方法

标签 c# asynchronous async-await task-parallel-library httpclient

我有这个异步方法:

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

该应用程序是一个网络后端 (WebApi)。

我做错了什么?

最佳答案

您的手上可能遇到了死锁。

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

但是最好避免在异步代码上同步阻塞,并为同步和异步设置两个不同的版本。

关于c# - 通过调用 <asyncmethod>.Result 实现同步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32608947/

相关文章:

javascript - 异步/等待在 reactjs 中不起作用(使用 npx create-react-app)

c# - 异步过程中的 DateTime 转换

c# - Unity)如何保持 Sprite 纵横比?

unit-testing - Nodejs 单元测试网址

c# - C#中的异步问题

asp.net-mvc - 在 MVC5 中使用异步有什么优势?

c# - 如何在波形的特定点播放mp3?

c# - 来自 HttpWebRequest 生命周期范围的响应流

javascript - 发送 ajax 请求而不等待回答

C# .NET 异步等待返回类型