5

I'm a little confused around the issue of returning a byte array vs a stream in an HTTP Response using .net Web API.

I came across the following code:

        SqlConnection conn = new SqlConnection();
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandText = "Select FileData.PathName() As FilePath, GET_FILESTREAM_TRANSACTION_CONTEXT() AS Context From FileStorage";
        conn.Open();
        SqlDataReader reader = cmd.ExecuteReader();
        reader.Read();
        string filePath = (string)reader["FilePath"];

        byte[] fileBytes = (byte[])reader["Context"];
        SqlFileStream stream = new SqlFileStream(filePath, fileBytes, FileAccess.Read);

        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");

Question 1: Why would they return a Stream instead of a byte array in the HTTP Response?

Question 2: Why create a SqlFileStream to read the data if the byte array is already available by calling (byte[])reader["Context"]? Wouldn't this mean that the entire file contents are read into memory? So why the need for a Stream?

2 Answers 2

5
+50

Question 1: Why would they return a Stream instead of a byte array in the HTTP Response?

Because the byte array may be huge, so if you read the entire array into the memory of the server and keep it in memory until it has all been transmitted to the client you are imposing a huge memory burden on the server. That's the stuff Denial-Of-Service attacks are made of. By using a stream you allow the server to load the data in small chunks, on an as-needed basis, and to keep only a small chunk in memory at any given time, while waiting for it to be transmitted.

Question 2: Why create a SqlFileStream to read the data if the byte array is already available by calling (byte[])reader["Context"]? Wouldn't this mean that the entire file contents are read into memory? So why the need for a Stream?

The byte array that you see there is not the actual file contents. If you look at the documentation of the constructor of SqlFileStream, and also at the documentation of the SqlFileStream class, this byte array is some "transaction context" which is (a terrible hack) necessary for the database server to read the actual the data from storage. The actual data is potentially huge, so the code that you posted does all this in order to avoid loading it all into memory.

Sign up to request clarification or add additional context in comments.

Comments

0

Buffering is the main reason for returning StreamContent. In ASP.NET Web API every time you return StreamContent, your response is not buffered however byte array response is already buffered and available to serve. In the case of byte[] the content of HttpResponseMessage could be set directly from your byte[] and you do not need to convert it to Stream type. In addition consider using PushStreamContent in scenarios in which you want to stream binary contents to the client continuously so client can consume your api progressively as the data arrives similar to following code snipet:

        var httpResponseMessage = new HttpResponseMessage
        {
            Content = new PushStreamContent(async (respStream, content, context) =>
            {
                using (var writer = new StreamWriter(respStream))
                {
                    await writer.WriteLineAsync();
                    await writer.FlushAsync();
                }
            }, "text/plain")
        };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.