SqlFileStream:HTTP响应中的返回流与字节数组

时间:2015-11-24 07:55:38

标签: bytearray asp.net-web-api2 asp.net-web-api httpresponse filestream

我对使用.net Web API在HTTP响应中返回字节数组与流的问题感到困惑。

我遇到了以下代码:

        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");

问题1: 为什么他们会在HTTP响应中返回Stream而不是字节数组?

问题2: 如果通过调用(byte[])reader["Context"]字节数组已经可用,为什么要创建 SqlFileStream 来读取数据?这不意味着整个文件内容被读入内存吗?那为什么需要Stream?

2 个答案:

答案 0 :(得分:2)

  

问题1:为什么他们会在HTTP响应中返回Stream而不是字节数组?

因为字节数组可能很大,所以如果你将整个数组读入服务器的内存并将其保存在内存中,直到它全部传输到客户端,就会给服务器带来巨大的内存负担。这就是拒绝服务攻击所构成的东西。通过使用流,您可以允许服务器根据需要以小块的形式加载数据,并在任何给定时间只在内存中保留一小块,同时等待它传输。

  

问题2:为什么创建一个SqlFileStream来读取数据,如果字节数组已经可以通过调用(byte [])阅读器[" Context"]?这不意味着整个文件内容被读入内存吗?那为什么需要Stream?

您看到的字节数组实际文件内容。如果您查看the documentation of the constructor of SqlFileStream以及the documentation of the SqlFileStream class,则此字节数组是某些"事务上下文"这是(一个可怕的黑客)数据库服务器从存储中读取实际数据所必需的。实际数据可能很大,因此您发布的代码会完成所有这些操作,以避免将其全部加载到内存中。

答案 1 :(得分:0)

缓冲是返回StreamContent的主要原因。在ASP.NET Web API 中,每次返回StreamContent时,您的响应都不会被缓冲但是字节数组响应已经缓冲并且可以提供服务。在byte []的情况下,HttpResponseMessage的内容可以直接从你的byte []设置,你不需要将它转换为Stream类型。 此外,考虑在您希望将二进制内容连续流式传输到客户端的情况下使用PushStreamContent,以便客户端可以在数据到达时逐步使用您的api,类似于以下代码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")
        };