Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient and PushStreamContent

I use PushStreamContent with my REST API (ASP.NET Web API) and works great. The HttpClient can request a ressource and gets the HTTP-Response before the complete request is handled by the server (the server still writes to the push-stream).

As HttpClient you have to do one little thing: Use HttpCompletionOption.ResponseHeadersRead.

Now my question: Is it possible to to this the other way? From the HttpClient -> uploading data via a push-stream to the web api?

I Implemented it as below, but the web api gets the request not before the client closes the stream.

         var asyncStream = new AsyncStream(fs);
         PushStreamContent streamContent = new PushStreamContent(asyncStream.WriteToStream);
         content.Add(streamContent);

         HttpResponseMessage response = await c.SendAsync(new HttpRequestMessage(new HttpMethod("POST"), "http://localhost/...") { Content = content }, HttpCompletionOption.ResponseHeadersRead);

         response.EnsureSuccessStatusCode();

The AsyncStream is my class with the delegate:

public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)

This is necessary for the Push-Stream.

Is this possible somehow? The HttpClient do not send the request to the web api until the last bytes are written to the stream...

What do I have to do? Is the problem on the client side or maybe on the server / asp.net web api-side?

Edit: This is the implemenation of WriteToStream (but I do not use a file from disk, is use a memorystream 'myMemoryStream' (passed in the constructor):

public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
    try
    {
        var buffer = new byte[4096];

        using (var stream = myMemoryStream)
        {
            var bytesRead = 1;

            while (bytesRead > 0)
            {
                bytesRead = video.Read(buffer, 0, buffer.Length);
                outputStream.Write(buffer, 0, bytesRead);
            }
        }
    }
    catch (HttpException ex)
    {
        return;
    }
    finally
    {
        outputStream.Close();
    }
}

Maybe I have to do something with: HttpContent content, TransportContext context ?

like image 799
user437899 Avatar asked Aug 21 '14 15:08

user437899


2 Answers

I found the solution to my problem:

I want to set: httpWebRequest.AllowReadStreamBuffering = false;

HttpClient 4.0 does buffering by default and you cannot acces the property AllowReadStreamBuffering, so you have to use HttpWebRequest directly. (Or you can use HttpClinet 4.5, there is the default behaviour 'streaming') see: http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ 6. Using HttpClient)

The second problem was fiddler: Fiddler currently only supports streaming of responses and not requests (Fiddler makes HttpWebRequest/HttpClient behaviour unexpected)

The solution that worked for me:

HttpWebRequest httpWebRequest = HttpWebRequest.Create(...)
httpWebRequest.Method = "POST";
         httpWebRequest.Headers["Authorization"] = "Basic " + ...;
         httpWebRequest.PreAuthenticate = true;
         httpWebRequest.AllowWriteStreamBuffering = false;
         httpWebRequest.AllowReadStreamBuffering = false;
         httpWebRequest.ContentType = "application/octet-stream";
         Stream st = httpWebRequest.GetRequestStream();
st.Write(b, 0, b.Length);
st.Write(b, 0, b.Length);
//...
         Task<WebResponse> response = httpWebRequest.GetResponseAsync();

         var x = response.Result;
         Stream resultStream = x.GetResponseStream();
//... read result-stream ...
like image 101
user437899 Avatar answered Nov 12 '22 06:11

user437899


Make sure to do requestMessage.Headers.TransferEncodingChunked = true; on your request message...the reason is if you do not set this, HttpClient would buffer the entire content at the client itself in order to figure out the Content-length of the request and this is the reason you are noticing your web api service not being invoked immediately as you are writing to the stream...

like image 20
Kiran Avatar answered Nov 12 '22 04:11

Kiran