HttpWebRequest 随机失败并等待异步
HttpWebRequest randomly fails with async and await
我想做几个POST-请求。
我的问题是在 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-Desktop 客户端 - 而不是服务器应用程序。所以这并没有什么帮助。
感谢您的帮助!
在你的 catch 块中你有 (HttpWebResponse)ex.Response
。
来自 MSDN:
If a response is available from the Internet resource, a WebResponse instance that contains the error response from an Internet resource; otherwise, null.
所以你的问题是服务器无响应和错误处理错误。
但是不要解决这个问题,查找 HttpClient 并编写一个新的 async Task<> DoPost(...)
.
解决方案
非常感谢 Henk Holterman。他建议我使用 HttpClient
而不是 HttpWebRequest
。对于像我一样有同样问题的每个人:您将获得作为 NuGet 包的 HttpClient。
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\" }"
);
// [...]
}
我想做几个POST-请求。
我的问题是在 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-Desktop 客户端 - 而不是服务器应用程序。所以这并没有什么帮助。
感谢您的帮助!
在你的 catch 块中你有 (HttpWebResponse)ex.Response
。
来自 MSDN:
If a response is available from the Internet resource, a WebResponse instance that contains the error response from an Internet resource; otherwise, null.
所以你的问题是服务器无响应和错误处理错误。
但是不要解决这个问题,查找 HttpClient 并编写一个新的 async Task<> DoPost(...)
.
解决方案
非常感谢 Henk Holterman。他建议我使用 HttpClient
而不是 HttpWebRequest
。对于像我一样有同样问题的每个人:您将获得作为 NuGet 包的 HttpClient。
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\" }"
);
// [...]
}