1

I am trying to get a reference to a response stream before its complete in windows phone 8.

In other .Net platforms you can do

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

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

For the purpose of creating Portable class libraries I've used the HttpClientLibrary from nuget.

This Adds ref to extensions assembly Microsoft.Net.Http

this allows me to return the async request at the time the headers have been read instead of waiting for the content transfer to be complete with

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

The problem I'm having is that in windows phone 8 it doesn't work correctly, and still awaits the completion of the content stream to return.

Additionally

await httpWebRequest.BeginGetResponse(callback, request) 

has the same behavior as these async methods are actually waiting for the completion of the web's response to continue execution.

So, is there any way to achieve the returning the response/stream at the point that i have received the response headers without Microsoft.Http.Net package? Even if it has to be a Windows Phone 8 Platform Specific Solution? Possibly an extension of HttpWebRequest?

Zack Weiner
  • 664
  • 4
  • 14
  • You could use `WebRequest.GetResponseAsync` like [this](http://stackoverflow.com/a/19215782/1768303), then `WebResponse.GetResponseStream`, then `Stream.ReadAsync`. – noseratio Jan 31 '14 at 12:10
  • Ive already seen that Stack overflow article. Its not written for Windows Phone 8, because the method GetResponseAsync for class HttpWebRequest does not exist in windows Phone 8. – Zack Weiner Jan 31 '14 at 12:29
  • @ZackWeiner What you are doing is the correct way of doing it. Are you sure it is not working? How big is your response body? How do you know it still awaits the "completion of the content stream"? – Darrel Miller Jan 31 '14 at 14:13
  • @DarrelMiller The connection Im working with should never be closed, its an endless stream that should stay open to get events sent from the server. So on the desktop with httpRequest.GetResponseStream() I can just read the stream until it ends. I know that the code is awaiting the content of the response, because on other platforms (WPF) var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead); returns nearly immediately, but on the Phone, the method only returns when the connection times out, or is explicitly closed (using GUI tool Fiddler). – Zack Weiner Jan 31 '14 at 15:00
  • @ZackWeiner You have inspired me to install the WP8 SDK. I need to try this myself. – Darrel Miller Jan 31 '14 at 15:48

2 Answers2

1

From what I can tell, ResponseHeadersRead works on the WP8 emulator as it does on the desktop.

I installed the Win8 SDK. Created a windows phone app. I added this code to the MainPage ctor. This demonstrates a very rudimentary long polling example.

      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;
   }

On my host dev machine I have a web api with a controller that looks like this...

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
            };
        }
    }
Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • are you actually able to read off of the stream? I popped this code into a sample app, and modified it to connect to my live SSE server, and I can see that execution continues beyond SendAsync as I have a simple string value assignment on the next line of execution... BUT Continuation1 seems to only execute in the case of an error, and not when a connection is made and data is send down the pipe...Therefore Continuation2 and ReadNextMessage() never fire. I can verify that data is coming down the connection using Fiddler's CommetPeek function (Right-Click on an open connection). – Zack Weiner Feb 02 '14 at 16:18
  • I was able to read the stream just fine. However this was only in the emulator. I don't have a phone developer account setup yet so I couldn't test it on real hardware. – Darrel Miller Feb 02 '14 at 16:22
  • Im also using the emulator, but had trouble with the localhost WebApi, so I created a new WebApi project, dropped your code in the get method and published it to the real deal world wide web. The route is http://www.thepartypedro.com/api/values and the code is identical to the api controller you supplied, can you confirm that you can read off that endpoint as well? If so, can we confirm you're also using Microsoft.Net.Http build 2.2.18 ? you can also confirm the get endpoint that is not long running @ http://thepartypedro.com/api/values/13 – Zack Weiner Feb 02 '14 at 22:27
  • ignore that last comment, after I realized I hadnt been working n the hardware I gave that a shot and it works well @ that thepartypedro/api/values endpoint. – Zack Weiner Feb 02 '14 at 22:32
  • @ZackWeiner So, you are now able to read the stream manually, after getting the headers back? – Darrel Miller Feb 02 '14 at 23:13
0

So here's the deal. I would say that what you want to do is not possible, due to platform limitations... But SignalR has a WP client and is able to manage it. So it seems to me you have two options:

1) Dig into the SignalR source code to see how they do it (I'm on my phone right now so I can't provide a link).

UPDATE: Here is the link. They do some pretty neat tricks, like setting the Timeout to -1 for long-running clients. I think you should definitely use the techniques here.

OR

2) You can move whatever you're doing over to SignalR, which would gain the benefit of having a robust infrastructure and being cross-platform compatible.

HTH

Robert McLaws
  • 2,258
  • 2
  • 19
  • 22
  • Although Im not that familiar with SignalR it appears as if SignalR is the backend service and the client. I.E. you need a server side component. I already have the server side implementation, and it works well on other platforms... I may just have to suck it up and listen over a socket. – Zack Weiner Jan 31 '14 at 16:19
  • Zack, I just updated my comment with the link. You should look at the SignalR source, I believe the techniques they use will definitely solve your problem. – Robert McLaws Jan 31 '14 at 18:14
  • HttpClient uses the Timeout -1 trick under the covers too. Setting timeout in HttpWebRequest only works properly when doing sync requests. – Darrel Miller Feb 01 '14 at 02:59