Caius
Caius

Reputation: 2264

How to read data from response stream HttpWebRequest C#

I'm building a Xamarin app. I'm still on a very very noobish level, and I'm coming from Nativescript, and something (not much) of Native Android.

I have an Express server that performs long-time operations. During that time the Xamarin client waits with a spinner.

On the server I already calculate the percentage progress of the job, and I'd like to send it to the client each time it changes, in order to swap that spinner with a progress.

Still, on the server, the task was already achieved with a response.write('10'); where the number 10 stands for "10%" of the Job done.

Now the tuff part. How can I read that 10 from the stream? Right now it works as a JSON response, because it waits for the whole response to come.

Xamarin client HTTP GET:

// Gets weather data from the passed URL.
async Task<JsonValue> DownloadSong(string url)
    {
        // Create an HTTP web request using the URL:
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
        request.ContentType = "application/json";
        request.Method = "GET";

    // Send the request to the server and wait for the response:
    using (WebResponse response = await request.GetResponseAsync())
    {
        // Get a stream representation of the HTTP web response:
        using (System.IO.Stream stream = response.GetResponseStream())
        {
            // Use this stream to build a JSON document object:
            JsonValue jsonDoc = await Task.Run(() => JsonValue.Load(stream));

            // Return the JSON document:
            return jsonDoc;
        }
    }
}

The server writes on the response each time the progress of the job changes, sending a plain string containing the percentage value. At the end of the job, it will write a final string, which will be a Base64 (very long) string. And the response will be then closed.

Can anyone indicate me how to change that script in order to read each data chunk the server sends?

Upvotes: 4

Views: 3542

Answers (1)

Evk
Evk

Reputation: 101613

First you need to define some protocol. For simplicity we can say that server sends:

  • (optional) current progress as 3-digit string ("010" - means 10%)
  • (required) final progress as "100"
  • (required) json data

So, valid response is, for example, "010020050090100{..json here..}".

Then you can read response in 3-byte chunks, until you find "100". Then you read json. Sample code:

using (System.IO.Stream stream = response.GetResponseStream()) {
    while (true) {
        // 3-byte buffer
        byte[] buffer = new byte[3];
        int offset = 0;
        // this block of code reliably reads 3 bytes from response stream
        while (offset < buffer.Length) {
            int read = await stream.ReadAsync(buffer, offset, buffer.Length - offset);
            if (read == 0)
                throw new System.IO.EndOfStreamException();
            offset += read;
        }
        // convert to text with UTF-8 (for example) encoding
        // need to use encoding in which server sends
        var progressText = Encoding.UTF8.GetString(buffer);
        // report progress somehow
        Console.WriteLine(progressText);
        if (progressText == "100") // done, json will follow
            break;
    }
    // if JsonValue has async api (like LoadAsync) - use that instead of
    // Task.Run. Otherwise, in UI application, Task.Run is fine
    JsonValue jsonDoc = await Task.Run(() => JsonValue.Load(stream));
    return jsonDOc;
}

Upvotes: 2

Related Questions