I am working with HttpClient and I want to get the stream response.
I want to make it work like Webresponse.getResponseStream() in order to read it in a BinaryReader like this :
BinaryReader reader = new BinaryReader(new BufferedStream(myWebResponse.GetResponseStream());
I have tried to use the GetStreamAsync, but it never works because I am forced to use await and the HttpResponseMessage gets bytes infinitely.
BinaryReader reader = new BinaryReader(new BufferedStream(await myHttpClient.GetStreamAsync());
I don't know how to use the CopyToAsync, so I don't know if it works..
Any idea ?
Edit : More details.
The method getStreamAsync works when I'm receiving one anwser, but since i'm receiving a live stream, I don't get the stream before the live ends !
Related
I'm exploring how to implement an HTTP server in C#. (And before you ask, I know there is Kestrel (and nothing else that isn't obsolete), and I want a much, much smaller application.) So, the response could be a Stream that cannot be seeked and has an unknown length. For this situation, chunked encoding can be used instead of sending a Content-Length header.
The response can also be compressed with gzip or br as indicated by the client. This can be accomplished with e.g. the GZipStream class. I had almost said "easily", because that's not really the case. I always find the GZipStream API confusing each time I use it. I usually bump into every exception there is until I finally get it right.
It seems like I can only write (push) to a GZipStream and the compressed data will trickle out the other end into the specified "base" stream. But that's not desirable because I can't just let the compressed data flow to the client. It needs to be chunked. That is, each bit of compressed data needs to be prefixed with its chunk size. Of course the GZipStream cannot produce that format.
Instead, I'd like to read (pull) from the compressing GZipStream, but that doesn't seem to be possible. The documentation says it will throw an exception if I try that. But there has to be some instance that brings the compressed bytes into the chunked format.
So how would I get the expected result? Can it even be achieved with this API? Why can't I pull from the compressing stream, only push?
I'm not trying to make up (non-functional) sample code because that would only be confusing.
PS: Okay, maybe this:
Stream responseBody = ...;
if (canCompress)
{
responseBody = new GZipStream(responseBody, CompressionMode.Compress); // <-- probably wrong
}
// not shown: add appropriate headers
while (true)
{
int chunkLength = responseBody.Read(buffer); // <-- not possible
if (chunkLength == 0)
break;
response.Write($"{chunkLength:X}\r\n");
response.Write(buffer.AsMemory()[..chunkLength]);
response.Write("\r\n");
}
response.Write("0\r\n\r\n");
Your usage of GZipStream is incomplete. While your input responseBuffer is the correct target buffer, you have to actually write the bytes TO the GZipStream itself.
In addition, once you are done writing, you must close the GZipStream instance to write all compressed bytes to your target buffer. This is the critical step because there is no such thing as "partial compression" of an input stream in GZip. You would have to analyze the entire input in order to properly compress it. As such, this is the critical missing link that MUST happen before you can continue to write the response.
Finally, you need to reset the position of your output stream so that you can read it into an intermediary response buffer.
using MemoryStream responseBody = new MemoryStream();
GZipStream gzipStream = null; // make sure to dispose after use
if (canCompress)
{
using MemoryStream gzipStreamBuffer = new MemoryStream(bytes);
gzipStream = new GZipStream(responseBody, CompressionMode.Compress, true);
gzipStreamBuffer.CopyTo(gzipStream);
gzipStream.Close(); // close the stream so that all compressed bytes are written
responseBody.Seek(0, SeekOrigin.Begin); // reset the response so that we can read it to the buffer
}
var buffer = new byte[20];
while (true)
{
int chunkLength = responseBody.Read(buffer);
if (chunkLength == 0)
break;
// write response
}
In my test example, my bytes input was 241 bytes, whereas the compressed bytes written to the buffer totaled 82 bytes.
I'm working with the Azure Relay Service at the moment and faced a problem handling the stream. I need to use this service in a synchronous way as it is required by the software which will use this implementation.
I'm opening a stream to the service and reading the data from it with StreamReader(), works fine. But now I must leave the StreamReader without closing the underlying stream as I have to send an answer back to the sender.
The problem is, that I can't leave the StreamReader() without closing the underlying stream and its not posible to reopen the stream to send an answer back.
Any ideas how to solve this problem?
Thanks for your help.
There is an overload of the StreamReader constructor which accepts a bool leaveOpen parameter. Passing true prevents the StreamReader from closing the stream when the StreamReader is disposed.
leaveOpen
Type: System.Boolean
true to leave the stream open after the StreamReader object is disposed; otherwise, false.
Example, using the default UTF8 encoding and 1024-byte buffer that you get with the simpler StreamReader constructors:
using (var reader = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
{
// use reader
} // stream will NOT be closed here
I totally hit my limit here:
I am working with an API that offers me this:
For a running event, the video images can be received in the form of a
continuous multipart stream. The stream ends as soon as the event
finishes.
Would would I capture this?
I started coding something like this:
System.Net.WebResponse res = req.GetResponse();
System.IO.Stream ReceiveStream = res.GetResponseStream();
using (System.IO.StreamReader sr = new System.IO.StreamReader(ReceiveStream, Encoding.UTF8))
which works like a charm, as long as there is only 1 response.
Could someone point me in the right direction?
I am trying to read a response from a server that I receive when I send a POST request. Viewing fiddler, it says it is a JSON response. How do I decode it to a normal string using C# Winforms with preferably no outside APIs. I can provide additional code/fiddler results if you need them.
The fiddler and gibberish images:
The gibberish came from my attempts to read the stream in the code below:
Stream sw = requirejs.GetRequestStream();
sw.Write(logBytes, 0, logBytes.Length);
sw.Close();
response = (HttpWebResponse)requirejs.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
MessageBox.Show(sr.ReadToEnd());
As mentioned in the comments, Newtonsoft.Json is really a good library and worth using -- very lightweight.
If you really want to only use Microsoft's .NET libraries, also consider System.Web.Script.Serialization.JavaScriptSerializer.
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
Going to assume (you haven't clarified yet) that you need to actually decode the stream, since A) retrieving a remote stream of text is well documented, and B) you can't do anything much with a non-decoded JSON stream.
Your best course of action is to implement System.Web.Helpers.Json:
using System.Web.Helpers.Json
...
var jsonObj = Json.Decode(jsonStream);
I am planning to pass MemoryStream via WCF Streaming but it seems not working but when I slightly change the code to pass FileStream instead, it is working. In fact, my purpose is to pass large collection of business objects (serializable). I am using basicHttpBinding. Your suggestion would be much appreciated!
Edited:
The symptoms of the issue is that the incoming stream is empty. There is neither error nor exception.
You're not providing many details, however, I'm almost certain I know what the issue is as I've seen that happening a lot.
If you write something to a MemoryStream in order to return that one as the result of a WCF service operation, you need to manually reset the stream to its beginning before returning it. WCF will only read the stream from it current position, hence will return an empty stream if that position hasn't been reset.
That would at least explain the problem you're describing. Hope this helps.
Here some sample code:
[OperationContract]
public Stream GetSomeData()
{
var stream = new MemoryStream();
using(var file = File.OpenRead("path"))
{
// write something to the stream:
file.CopyTo(stream);
// here, the MemoryStream is positioned at its end
}
// This is the crucial part:
stream.Position = 0L;
return stream;
}