【问题标题】:Reading the content of HTTP Stream before the Content stream is Complete Windows Phone 8在内容流完成之前读取 HTTP 流的内容 Windows Phone 8
【发布时间】:2014-01-30 23:34:44
【问题描述】:

我正在尝试在 windows phone 8 中完成之前获取对响应流的引用。

在其他.Net平台上你可以做

HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(myUri);
WebResponse subscribeWebResponse = null;
Stream subscribeStream = null;

subscribeWebResponse = httpRequest.GetResponse();
subscribeStream = subscribeWebResponse.GetResponseStream();

为了创建可移植类库,我使用了 nuget 的 HttpClientLibrary。

这会将引用添加到扩展程序集 Microsoft.Net.Http

这允许我在读取标头时返回异步请求,而不是等待内容传输完成

var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead);

我遇到的问题是在 windows phone 8 中它无法正常工作,并且仍在等待内容流完成返回。

另外

await httpWebRequest.BeginGetResponse(callback, request) 

与这些异步方法具有相同的行为,实际上是在等待网络响应完成以继续执行。

那么,在我收到没有 Microsoft.Http.Net 包的响应标头时,有什么方法可以实现返回响应/流? 即使它必须是 Windows Phone 8 平台特定解决方案? 可能是 HttpWebRequest 的扩展?

【问题讨论】:

  • 你可以使用WebRequest.GetResponseAsync,比如this,然后是WebResponse.GetResponseStream,然后是Stream.ReadAsync
  • 我已经看过那篇堆栈溢出文章。它不是为 Windows Phone 8 编写的,因为 Windows Phone 8 中不存在类 HttpWebRequest 的 GetResponseAsync 方法。
  • @ZackWeiner 您正在做的是正确的做法。你确定它不工作吗?你的响应体有多大?你怎么知道它还在等待“内容流的完成”?
  • @DarrelMiller 我使用的连接不应该关闭,它应该保持打开状态以获取从服务器发送的事件。所以在桌面上使用 httpRequest.GetResponseStream() 我可以读取流直到它结束。我知道代码正在等待响应的内容,因为在其他平台(WPF)上 var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead);几乎立即返回,但在电话上,该方法仅在连接超时或显式关闭时返回(使用 GUI 工具 Fiddler)。
  • @ZackWeiner 你启发了我安装 WP8 SDK。我需要自己尝试一下。

标签: windows-phone-8 httpwebrequest async-await dotnet-httpclient


【解决方案1】:

据我所知,ResponseHeadersRead 在 WP8 模拟器上的工作方式与在桌面上的工作方式相同。

我安装了 Win8 SDK。创建了一个 Windows Phone 应用程序。我将此代码添加到 MainPage ctor。这演示了一个非常基本的长轮询示例。

      var client = new HttpClient();

        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri("http://oak:1001/longpolling")
        };
        client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, new CancellationToken())
            .ContinueWith((t) =>
            {
                var response = t.Result;
                response.Content.ReadAsStreamAsync()
                    .ContinueWith(s =>
                    {
                        var st = s.Result;
                        while (true)
                        {
                            var message= ReadNextMessage(st);
                        }
                    });       
            });
  }
   private static string ReadNextMessage(Stream stream)
        {
            int chr = 0;
            string output = "";
            while (chr != 10)
            {
                chr = stream.ReadByte();
                output += Convert.ToChar(chr);
            }
            return output;
   }

在我的主机开发机器上,我有一个带有控制器的 web api,看起来像这样......

public class LongPollingController : ApiController
    {
        public HttpResponseMessage Get()

        {
            Thread.Sleep(2000);
            var content = new PushStreamContent( (s,c,t) =>
            {
                int i = 0;
                while (true)
                {
                    try
                    {
                        var message = String.Format("The current count is {0} " + Environment.NewLine, i++);
                        var buffer = Encoding.UTF8.GetBytes(message);
                        s.Write(buffer, 0, buffer.Length);
                    }
                    catch (IOException exception)
                    {
                        s.Close();
                        return;
                    }
                    Thread.Sleep(1000);
                }
            });
            return new HttpResponseMessage(HttpStatusCode.OK)
            {
                RequestMessage = Request,
                Content = content
            };
        }
    }

【讨论】:

  • 您真的可以从流中读取吗?我将此代码弹出到一个示例应用程序中,并对其进行了修改以连接到我的实时 SSE 服务器,我可以看到执行超出了 SendAsync,因为我在下一行执行中有一个简单的字符串值分配......但 Continuation1 似乎仅在发生错误的情况下执行,而不是在建立连接并通过管道发送数据时执行...因此,Continuation2 和 ReadNextMessage() 永远不会触发。我可以使用 Fiddler 的 CommetPeek 功能(右键单击打开的连接)验证数据是否从连接中传出。
  • 我能够很好地读取流。但是,这仅在模拟器中。我还没有设置手机开发者帐户,因此无法在真实硬件上进行测试。
  • 我也在使用模拟器,但在使用 localhost WebApi 时遇到了问题,所以我创建了一个新的 WebApi 项目,将您的代码放在 get 方法中并将其发布到真实的万维网。路由是thepartypedro.com/api/values,代码与您提供的 api 控制器相同,您能否确认您也可以读取该端点?如果是这样,我们能否确认您也在使用 Microsoft.Net.Http build 2.2.18 ?也可以确认get端点没有长时间运行@thepartypedro.com/api/values/13
  • 忽略最后一条评论,在我意识到我没有在硬件上工作之后,我试了一下,它运行良好@thepartypedro/api/values 端点。
  • @ZackWeiner 那么,您现在可以在取回标头后手动读取流了吗?
【解决方案2】:

所以这就是交易。我想说的是,由于平台限制,您想要做的事情是不可能的......但是 SignalR 有一个 WP 客户端并且能够管理它。所以在我看来你有两个选择:

1) 深入研究 SignalR 源代码,看看他们是如何做到的(我现在正在使用手机,所以无法提供链接)。

更新: Here is the link。他们做了一些非常巧妙的技巧,比如将 Timeout 设置为 -1 用于长时间运行的客户端。我认为你绝对应该使用这里的技术。

2) 您可以将正在做的任何事情转移到 SignalR,这将受益于拥有强大的基础架构和跨平台兼容。

HTH

【讨论】:

  • 虽然我对 SignalR 不是很熟悉,但它看起来好像 SignalR 是后端服务和客户端。 IE。你需要一个服务器端组件。我已经有了服务器端的实现,它在其他平台上也能很好地工作……我可能只需要把它吸起来,然后通过一个套接字来监听。
  • 扎克,我刚刚用链接更新了我的评论。你应该看看 SignalR 源码,我相信他们使用的技术一定能解决你的问题。
  • HttpClient 在幕后也使用了 Timeout -1 技巧。在 HttpWebRequest 中设置超时仅在执行同步请求时才能正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多