我已经查看了类似问题的一些答案,似乎找不到适合我正在做的事情。我需要使用HttpWebRequest做一些同步请求(一些使用每个动词,GET / PUT / POST / DELETE)并且似乎无法让它工作。当我手动使用设计中的“刷新”按钮(适用于任何指定的动词)时,下面的示例效果很好,但是当我取消注释“b_send_Click”中的部分时它不起作用。我正在寻找的是一个封装REST客户端的封装方法(在这个例子中'b_send_Click'的方式),然后在调用完成时采取一些动作(以'b_send_Click'中的注释部分为例)。有任何想法吗?顺便说一下,这可以作为异步REST调用的包装,但我无法使同步工作......
using Microsoft.Phone.Controls;
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Windows;
namespace WP8Rest
{
public partial class MainPage : PhoneApplicationPage
{
// global variables
public static string url = "http://mywebsite.com/API/some_api";
public static string request_body = "";
public static HttpWebRequest client = null;
public static HttpWebResponse response = null;
public static string server_response = "";
public static bool request_done = false;
public MainPage()
{
InitializeComponent();
}
private void b_send_Click(object sender, RoutedEventArgs e)
{
rest_request(sender, e);
/*
while (!request_done)
{
Thread.Sleep(100);
}
if (response != null)
{
l_status_code.Text = response.StatusCode.ToString();
l_status_description.Text = response.StatusDescription.ToString();
l_response.Text = server_response;
}
else
{
l_status_code.Text = "0";
l_status_description.Text = "Unable to complete request...";
l_response.Text = "Unable to complete request...";
}
*/
}
private void rest_request(object sender, RoutedEventArgs e)
{
request_done = false;
server_response = "";
request_body = tb_reqbody.Text;
client = (HttpWebRequest)WebRequest.Create(url);
client.Method = tb_verb.Text;
client.AllowAutoRedirect = true;
switch (tb_verb.Text)
{
case "GET":
client.BeginGetResponse(new AsyncCallback(GetResponseCallback), client);
break;
case "PUT":
client.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), client);
client.ContentType = "application/json";
break;
case "POST":
client.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), client);
client.ContentType = "application/json";
break;
case "DELETE":
client.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), client);
client.ContentType = "application/json";
break;
default:
MessageBox.Show("Use GET, PUT, POST, or DELETE.");
return;
}
l_response.Text = "Request sent...";
return;
}
private static void GetRequestStreamCallback(IAsyncResult async_result)
{
HttpWebRequest request = (HttpWebRequest)async_result.AsyncState;
Stream request_body_stream = request.EndGetRequestStream(async_result);
byte[] request_body_bytearray = Encoding.UTF8.GetBytes(request_body);
request_body_stream.Write(request_body_bytearray, 0, request_body.Length);
request_body_stream.Close();
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult async_result)
{
HttpWebRequest request = (HttpWebRequest)async_result.AsyncState;
response = (HttpWebResponse)client.EndGetResponse(async_result);
Stream response_body_stream = response.GetResponseStream();
StreamReader stream_reader = new StreamReader(response_body_stream);
server_response = stream_reader.ReadToEnd();
response_body_stream .Close();
stream_reader.Close();
response.Close();
request_done = true;
}
private void b_refresh_Click(object sender, RoutedEventArgs e)
{
if (response != null)
{
l_response.Text = server_response;
l_status_code.Text = response.StatusCode.ToString();
l_status_description.Text = response.StatusDescription.ToString();
}
else
{
l_response.Text = "No response...";
}
}
}
}
Per @ Industry86我能够安装Microsoft.Net.Http。将代码更改为:
private async void b_send_Click(object sender, RoutedEventArgs e)
{
l_response.Text = myMethod();
}
async Task<string> myMethod()
{
string address = "http://dev.getcube.com:65533/rest.svc/API/mirror";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(address);
string responseText = await response.Content.ReadAsStringAsync();
return responseText;
}
现在问题是它不会编译 - “无法将类型'System.Threading.Tasks.Task'隐式转换为'string'。我将b_send_Click中的行更改为l_response.Text = (myMethod()).Result;
(不确定这是否是是否正确)当我点击“b_send”按钮时,它变为橙色,服务器永远不会看到请求。
答案 0 :(得分:2)
创建新答案以专注于代码更改。
在异步方法调用前放置await
:
private async void b_send_Click(object sender, RoutedEventArgs e)
{
l_response.Text = await myMethod();
}
当您使用.Result
时,它会暂停该过程,直到结果返回,从而停止UI和其他所有内容。这是一个SO答案,详细说明了这个问题:
https://stackoverflow.com/a/13703845/311393
快速课程:使用void返回值,异步方法将“即发即忘”并且永远不会期望返回。使用Task
或Task<T>
返回值时,调用的异步方法将暂停调用方法,直到完成为止。
因此b_send_Click
将触发一个线程来做任何事情。当它使用适当的myMethod()
关键字调用await
(任务)时,它将以同步方式停止并等待它完成无论它正在做什么。
并且myMethod()
有多个异步方法调用,但是那些也在等待它们,所以线程也会等待那些同步完成。
然后它返回到你的文本字段和UI,我假设在WP8中,异步地监听对它的文本字段的更改。
答案 1 :(得分:1)
就个人而言,我会使用Windows 8中存在的HTTPClient(它非常棒),如果尚未完全发布,目前可能仍然处于WP8(https://nuget.org/packages/Microsoft.Net.Http)的测试阶段。语法更小更简单。 或者使用RestSharp(http://restsharp.org/),但async / await的东西并不健全。 RestSharp非常擅长序列化。
说,你还需要了解异步操作是如何发生的。您正在调用异步操作,并在没有“等待”的情况下继续前进。因此:
l_response.Text = server_response;
将不会被设置,因为如果没有Thread.Sleep(100),代码将触发异步调用并继续前进,并且server_response在到达时仍然是 null 一部分。
如果你想等待该调用的返回,你需要使用“await”命令并在方法声明中包含异步指示符并返回一个Task(其中object可以是你想要的任何东西)返回)。使用HttpClient的示例:
async Task<string> myMethod()
{
string address = "http://mywebsite.com/API/some_api";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(address);
string responseText = await response.Content.ReadAsStringAsync();
return responseText;
}
并且生成的字符串“responseText”将具有要解析的JSON内容。当然,如果你正在寻找一个流,它也在那里。
你还必须记住,这个方法本身需要来自UI线程的等待,并且声明将需要是异步的:
private async void b_send_Click(object sender, RoutedEventArgs e)
{
someTextBox.Text = myMethod();
}
和事件处理程序通常应该是唯一返回 void 的异步方法。