2013-04-29 87 views
-2

我已经查看了类似问题的一些答案,似乎无法找到适用于我所做的事情。我需要使用HttpWebRequest(一些使用每个动词,GET/PUT/POST/DELETE)进行一些同步请求,似乎无法使其工作。当我手动使用设计中的“刷新”按钮(适用于任何指定的动词)时,下面的示例非常适用,但是当我取消注释“b_send_Click”中的部分时,它不起作用。我正在寻找的是一个封装方法,它将封装REST客户端(在本例中为'b_send_Click'),然后在调用完成时采取一些操作(例如,'b_send_Click'中的注释部分)。有任何想法吗?顺便说一句,这个工程以及用于异步REST调用的包装,但我不能得到同步工作...需要在WP8中使用HttpWebRequest进行同步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..."; 
      } 
     } 
    } 
} 

每@ 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’到‘字符串’我改变了线b_send_Click到l_response.Text = (myMethod()).Result;(不。确定这是否正确),当我点击'b_send'按钮时,它变成橙色,服务器从未看到请求。

+1

好吧,忘了吧..... – I4V 2013-04-29 20:00:25

回答

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返回值,一个异步方法将“失火”,永远不会期望返回。使用TaskTask<T>返回值,调用的异步方法将暂停调用方法直到它完成。

因此b_send_Click会启动一个线程做任何事情。当它使用await关键字调用myMethod()(这是一项任务)时,它将以同步方式停止并等待它完成任何操作。

myMethod()有多个异步方法调用,但那些也有它们的等待,所以线程会等待那些同步完成。

然后它会返回到您的文本字段,并且我假设在WP8中的UI异步侦听对其文本字段的更改。

+0

HttpClient +你的答案做到了。我会看看我是否可以从这里进行修改,以适应我的需求。再次感谢! – joelc 2013-04-29 22:44:55

+1

噢好。很高兴为你工作。祝你好运! – Industry86 2013-04-29 22:47:15

1

就个人而言,我会使用Windows 8中存在的HTTPClient(这非常棒)如果尚未完全发布,目前可能还处于测试阶段(https://nuget.org/packages/Microsoft.Net.Http)。语法更小更简单。 或使用RestSharp(http://restsharp.org/),但异步/等待凝灰岩不够健壮。尽管RestSharp在序列化方面非常出色。

表示,您还需要了解异步操作是如何发生的。您正在调用异步操作并继续前进,而没有“等待”。因此:

l_response.Text = server_response; 

将被设置,因为,没有Thread.sleep代码(100),代码将已经发了异步调用,并继续前进,server_response仍然会通过它到达的时间那部分。

如果您想要等待该调用的返回,则需要使用“await”命令并在方法声明中包含异步指示符并返回Task(其中对象可以是您想要的任何对象回来)。使用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线程需要的await和声明将被要求为异步:

private async void b_send_Click(object sender, RoutedEventArgs e) 
{ 
    someTextBox.Text = myMethod(); 
} 

和事件处理程序通常应是唯一的异步方法是返回void

+0

不幸的是,Microsoft.Net.Http并没有在NuGet上用于WP8: - /如何更改上面的代码?干杯 – joelc 2013-04-29 20:28:38

+0

我刚刚创建了一个新的WP8应用程序,使用了链接中提供的安装命令,我提供了从Nuget获取该库的方法,从Windows 8应用程序中获取了一个方法,在构建PostAsync(复制/粘贴我可能从Windows 8应用程序添加到此Windows Phone 8应用程序)并返回有效的json。 很确定它现在在Nuget上。而且很确定它就像一个魅力。 如果你想使用你现有的代码,我不熟悉那个库,所以我不能回答它。 – Industry86 2013-04-29 20:51:52

+0

使用'Install-Package Microsoft.Net.Http -Pre'命令并失败。无法安装软件包'Microsoft.Bcl 1.0.19'。您正尝试将此软件包安装到目标为“WindowsPhone,Version = v8.0”的项目中,但该软件包不包含任何与该 框架兼容的程序集引用。有关更多信息,请联系软件包作者。 – joelc 2013-04-29 21:03:01

相关问题