【问题标题】:HttpWebRequest randomly fails with async and awaitHttpWebRequest 随机失败并异步等待
【发布时间】:2017-09-20 12:54:39
【问题描述】:

我想做几个 POST-Request。

我的问题是应用程序在我的async void bt_publishPath_Click()-Event 中的await 期间在Task<...> do_POST()-Function 中随机崩溃。

我可以做一些 POST 请求(一切正常),有时await 会阻塞,应用程序会因System.NullReferenceException 而崩溃(经过长时间的等待)。我不明白为什么会这样,因为它第一次工作。

这是我目前得到的结果

我已经注释掉了所有不重要的功能。我已经在没有这些代码行的情况下测试了我的代码,并且也发生了错误。

// MainWindow
private async void bt_publishPath_Click(object sender, RoutedEventArgs e)
{
    // gr_spinner.Visibility = Visibility.Visible;

    ApiResponse res = await ApiCall.do_POST(
        "/path",
        getBasicAuthString(),
        flink.getJsonString()
    );

    // gr_spinner.Visibility = Visibility.Collapsed;
    // Globals.errorHandling(res.Statuscode, res.Parameters[0]);
}

// ApiCall static Class
public static Task<ApiResponse> do_POST(string apiPath, string auth, string json)
{
    return Task.Run(() =>
    {
        int statuscode = 0;
        HttpWebResponse response = null;
        try
        {
            // HEADER
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiBase + apiPath);
            request.Method = "POST";
            request.ContentType = "application/json";
            request.Headers.Add("Authorization", auth);

            // DATA
            byte[] data = Encoding.ASCII.GetBytes(json);
            request.ContentLength = data.Length;
            Stream requestStream = request.GetRequestStream();
            requestStream.Write(data, 0, data.Length);
            requestStream.Close();

            // SEND AND GET RESPONSE
            /*
             * It seems to be that GetResponse() isn't called correctly.
             * The Backend doesn't receive a POST-request and the reponse stays null.
             */
            response = (HttpWebResponse)request.GetResponse();
            statuscode = (int)response.StatusCode;
        }
        catch (WebException ex)
        {
            statuscode = (int)((HttpWebResponse)ex.Response).StatusCode;
        }
        return new ApiResponse(statuscode, null, new String[] { apiPath });
    });
}

其他信息

在使用 async 和 await 执行此操作之前,我尝试使用 BackgroundWorker 解决此问题。在这种情况下,我遇到了类似的问题:有时上一个 POST 的 backgroundWorker 仍然很忙,程序无法启动一个新的(死锁)。

我还发现了一些有趣的东西:async await Task null reference exception

  • 但在这种情况下,它是一个 ASP.NET 应用程序。我正在开发一个 Windows 桌面客户端 - 而不是服务器应用程序。所以这并没有真正的帮助。

感谢您的帮助!

【问题讨论】:

  • 为什么ApiResponse res = task.Result;当你是await呢?
  • 1) 你不应该在异步方法中调用.Result
  • 2) 你不应该使用async void,除了按钮_点击这里。你忘记发了。它是必不可少的,因为它是调用树的根。
  • 按钮点击方法是异步的吗?你怎么称呼postAsync?您的代码是同步和异步的真正不必要的混搭。
  • @Rahul 在等待之后调用。我不知道获得结果的另一种方法。

标签: c# .net wpf asynchronous .net-4.5


【解决方案1】:

在您的 catch 块中,您有 (HttpWebResponse)ex.Response

来自MSDN

如果来自 Internet 资源的响应可用,则为包含来自 Internet 资源的错误响应的 WebResponse 实例;否则为空。

因此,您的问题是服务器无响应,并且您的错误处理存在错误。
但是不要解决这个问题,查找 HttpClient 并写一个新的async Task&lt;&gt; DoPost(...)

【讨论】:

  • 谢谢! HttpClient 解决了我的问题。我已经更新了我的问题并添加了解决方案。
  • 您可以将您的解决方案发布为自我回答,这是此处的首选。
【解决方案2】:

解决方案

非常感谢 Henk Holterman。他建议我使用HttpClient 而不是HttpWebRequest。对于像我一样遇到同样问题的每个人:您将获得 HttpClient 作为 NuGet-Package。

ApiCall.cs

private static HttpClient httpClient = new HttpClient();

public static async Task<HttpResponseMessage> do_POST(string apiPath, string auth, string json)
{
    HttpResponseMessage response;
    StringContent request = new StringContent(json);
    request.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
    try
    {
        response = await httpClient.PostAsync(new Uri(apiBase + apiPath), request);
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine(ex.Message);
        return null;
    }
    return response;
}

MainWindow.cs

private async void bt_publishPath_Click(object sender, RoutedEventArgs e)
{
    // [...]
    HttpResponseMessage res = await ApiCall.do_POST(
        "/path",
        "admin:123456",
        "{ \"hello\" : \"world\" }"
    );
    // [...]
}

【讨论】:

  • 感谢您链接到这篇非常有趣的文章!实际上我已经考虑过这一点——但后来我看到每个人都在使用 using 指令,并决定像所有其他人一样这样做。但这篇文章说服我改变我的代码。
猜你喜欢
  • 2018-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-09
  • 1970-01-01
  • 2018-04-05
  • 2023-03-12
相关资源
最近更新 更多