在析构函数中使用 HttpClient

Using HttpClient in destructor

我想在我的程序结束时 post 向服务器发送一些异常数据(如果存在)。

我有一个在主 window 视图模型析构函数上触发的析构函数..

我运行这个:

 ~ProgramWizardViewModel()
 {
    if ((Program.Errors.Count > 0)
                     && (WizardData?.User != null))
    {
        string errorsText = string.Format(string.Join("\n", Program.Errors));
        WizardData.client.UploadExceptionReport(errorsText);
    }
}

WizardData.client 有一个方法 UploadExceptionReport(我从 SO 复制的)

public void UploadExceptionReport(String s)
{
    using (var client = new HttpClient())
    {
        var uri = new Uri(Program.ServerUri + "api/exception_report");
        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("exception_string", s)
        });
        var result = client.PostAsync(uri, content).Result;
        string resultContent = result.Content.ReadAsStringAsync().Result;
        Console.WriteLine(resultContent);
    }
}

但是在 client.PostAsync,调试完全停止,无一例外,并且 returns:

The program '[3364] Program.vshost.exe' has exited with code 0 (0x0).

我猜这是因为异步的方式。 POST 使一个线程发送它的请求,但是析构函数结束并且对象在它可以执行之前就丢失了。

那么:什么是 POST 程序关闭时此数据的好方法? 此代码失败的原因可能是什么?

尝试让它异步。

~ProgramWizardViewModel()
{
    if ((Program.Errors.Count > 0)
                     && (WizardData?.User != null))
    {
        string errorsText = string.Format(string.Join("\n", Program.Errors));
        WizardData.client.UploadExceptionReport(errorsText).Wait();
    }
}

public async Task UploadExceptionReport(String s)
{
    using (var client = new HttpClient())
    {
        var uri = new Uri(Program.ServerUri + "api/exception_report");
        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("exception_string", s)
        });
        var result = await client.PostAsync(uri, content);
        string resultContent = await result.Content.ReadAsStringAsync();
        Console.WriteLine(resultContent);
    }
}

也许现在析构函数将等待 http 客户端异步任务完成。

你做错地方了。

您应该覆盖 OnFormClosing 方法或为 OnClosing 事件设置处理程序。

这样做的原因是您不需要在用户界面中出现任何随机的怪异现象——您尝试进行的日志记录应该发生在程序运行时间 之间 (或用户)调用 "close",但在表单从视图中消失之前。您甚至可以将鼠标指针更改为 "Timer"。如果您执行异步日志记录,请考虑是否在它发生时重复调用 DoEvents,以防止 UI 在 HTTP 请求需要一段时间时看起来已被锁定。

OnFormClosing:https://msdn.microsoft.com/en-us/library/system.windows.forms.form.onformclosing(v=vs.110).aspx

关闭时:https://msdn.microsoft.com/en-us/library/system.windows.forms.form.closing(v=vs.110).aspx

DoEvents:https://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents(v=vs.110).aspx