【问题标题】:ObjectDisposedException after second async call第二次异步调用后的 ObjectDisposedException
【发布时间】:2021-07-19 21:20:38
【问题描述】:

我正在尝试多次发送 HTTP POST 请求,但不是并行发送。我创建了另一个类并将这个函数放入其中:

    public async Task<string> sendReqAsync()
            {
               
                requestTime = DateTime.Now;
                var task = await client.PostAsync("https://api.example.com", content).ContinueWith(async (result) =>
                {
                    responseTime = DateTime.Now;
                    return await result.Result.Content.ReadAsStringAsync();
                    
                });
                
                return task.Result;
            }

最后它会在一个按钮的点击事件中被调用:

private async void ManualSendBtn_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // Here "client" is object of my class that have been initilized in the main WPF function
            await client.sendReqAsync().ContinueWith((result) =>
            {
                var parsedResponse = JObject.Parse(result.Result);

                this.Dispatcher.Invoke(() =>
                {
                    ordersListView.Items.Add(new OrderDetailsItem
                    {
                        IsSuccessful = bool.Parse(parsedResponse["IsSuccessfull"].ToString()),
                        ServerMessage = parsedResponse["MessageDesc"].ToString(),
                        RequestTime = client.requestTime.ToString("hh:mm:ss.fff"),
                        ResponseTime = client.responseTime.ToString("hh:mm:ss.fff"),
                        ServerLatency = (client.responseTime - client.requestTime).Milliseconds.ToString()
                    });

                });

            });
        }

但它只适用于第一次点击(事件发生),而下次点击它会给我:

内部异常 1:AggregateException:发生一个或多个错误。

内部异常 2:AggregateException:发生一个或多个错误。

内部异常 3:ObjectDisposedException:无法访问已处置的 对象。


编辑:以下是建议的编辑代码,但错误未修复。

MyHTTPClient

public class MyHTTPClient
    {
        private static readonly HttpClient client = new HttpClient();
        

        StringContent content;
        public DateTime requestTime;
        public DateTime responseTime;

        public void configureReq(string oauthToken)
        {
            var postBodyJSONObject = new
            {
                body = "value"
            };

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", oauthToken);

            content = new StringContent(JsonConvert.SerializeObject(postBodyJSONObject), Encoding.UTF8, "application/json");
        }


        public async Task<string> sendReqAsync()
        {
            requestTime = DateTime.Now;
            var result = await client.PostAsync("https://example.com", content);
            responseTime = DateTime.Now;

            return await result.Content.ReadAsStringAsync();
        }


    }

这也是我的窗口初始化函数:

MyHTTPClient client; // Somewhere in the class
public MainWindow() {
  client = new MyHTTPClient();
  client.configureReq(AUTHORIZATION);
}

【问题讨论】:

  • 您使用了async/await 错误。你根本不应该打电话给ContinueWith。删除所有ContinueWith 调用并用正确的async/await 代码替换它。像这样:``` requestTime = DateTime.Now; var result = await client.PostAsync("api.example.com", content); var responseTime = DateTime.Now;返回结果.Content.ReadAsStringAsync(); ```
  • 不要将await 与ContinueWith 混用。很确定PostAsync 将首先完成result.Result.Content.ReadAsStringAsync 运行第二个因此错误。在错误处理方面,延续可能是邪恶的
  • 另外,请改掉拨打task.Result的习惯。一般来说,最好使用(在你的情况下)return await client.PostAsync(因此不需要 var task = ...)
  • @Neistow 但我需要跟踪我的POST 请求的发送和接收时间。还有另一个好主意来实现这一目标吗?您能否更详细地描述一下?为什么我使用 async/await 错误?怎么写?

标签: c# asynchronous


【解决方案1】:

首先:您不应该混合使用不同的异步编程模型。 在您的代码中,您尝试将 async/await 与旧版 ContinueWith 方法结合使用。

您可以阅读更多关于async/await 方法here 以及关于async/await 和ContinueWith 差异here 的信息(感谢 MickyD 在 cmets 中留下指向此的链接)。

长话短说,您的代码应该如下所示:

public async Task<string> SendRequestAsync()
{
    requestTime = DateTime.Now;
    var response = await client.PostAsync("api.example.com", content); 
    var responseTime = DateTime.Now; 
    return await response.Content.ReadAsStringAsync();
}

请注意,现在代码看起来更像是同步的,并且比带有ContinueWith 的回调更易读。

您可以在 MSDN 上找到更多关于 C# 异步编程的信息。我建议您先阅读并尝试在控制台应用程序中执行一些代码,然后再将其写入您的主应用程序。

【讨论】:

  • 你不是在result.Content.ReadAsStringAsync(); 之前缺少await 吗?顺便说一句,result 变量的更好名称是 response 恕我直言。
  • @TheodorZoulias 是的,已更正。
【解决方案2】:

除了修复 SendRequestAsync 方法,如 Neistow 的 answer 所示,您还必须修复按钮的点击处理程序:

private async void ManualSendBtn_PreviewMouseLeftButtonUp(object sender,
    MouseButtonEventArgs e)
{
    string response = await client.SendRequestAsync();
    var parsedResponse = JObject.Parse(response);
    ordersListView.Items.Add(new OrderDetailsItem
    {
        IsSuccessful = bool.Parse(parsedResponse["IsSuccessfull"].ToString()),
        ServerMessage = parsedResponse["MessageDesc"].ToString(),
        RequestTime = client.RequestTime.ToString("hh:mm:ss.fff"),
        ResponseTime = client.ResponseTime.ToString("hh:mm:ss.fff"),
        ServerLatency = (client.ResponseTime - client.RequestTime).Milliseconds.ToString()
    });
}

没有理由与Dispatcher.Invoke 混淆。 await 之后的代码将继续在 UI 线程上运行,因为它默认发生在所有 Windows 窗体和 WPF 应用程序中。

【讨论】:

  • 你是对的,但实际上错误不是因为那个。 MyHTTPClient 有一个 content 变量,它在第一个窗口加载时初始化它的值。我将它的位置更改为我的sendReqAsync() 函数,它现在可以工作了!虽然不知道是什么原因!
猜你喜欢
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 2019-02-12
相关资源
最近更新 更多