从内存

时间:2017-11-29 22:33:55

标签: c# asp.net vb.net asp.net-web-api

我有一个数据库,其中有一个表,其中包含大约200多个记录,大约有20列。用户可以查询数据库并限制返回的记录数,因此记录集可能是1到2百万。

由于是表格信息,我想以CSV格式发送数据。我使用StreamWriter将数据写入内存,一旦文件完成,我将其作为HttpResponseMessage发送。我的代码如下,只要我的内存耗尽,它就能正常工作。有没有办法让我在处理文件时对其进行流式处理,以便使用的内存最少?

<HttpGet, Route("api/records/export")>
Public Function ExportRecords() As HttpResponseMessage

    Dim stream As New MemoryStream
    Dim writer As New StreamWriter(stream)
    writer.WriteLine("")

    ' Processing of data here
    writer.WriteLine("""Write Data to MemoryStream"")

    writer.Flush()
    stream.Position = 0

    Dim result As New HttpResponseMessage(HttpStatusCode.OK)
    result.Content = New StreamContent(stream)
    result.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("text/csv")
    result.Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment") _ 
        With {.FileName = "I" & Format(Date.Now, "yyMMdd") & ".csv"}

    Return result

End Function

我已经阅读了StackOverflow对Returning binary file from controller in ASP.NET Web API等问题的回答,但这些都涉及从存储在磁盘而不是内存中的文件中传输Web响应。

1 个答案:

答案 0 :(得分:1)

由于对我的问题的评论建议我使用PushStreamContent以CSV格式将我的数据库内容流式传输到浏览器。我还使它异步,以便从导出中获得更多性能。

使用PushStreamContent从服务器向客户端传输内容存在一个重要的限制。由于200 OK标题是在流式传输之前首先发送的,因此如果返回结果中的结果中出现错误,则响应不会提前知道。如果在发送结果时出现问题,客户端将在其结尾处看到一般网络错误。它由服务器记录任何错误,以便您可以检查服务器日志以查找特定错误。

以下是我使用的PushStreamContent代码(为简洁起见,删除了错误检查)。

Dim result As HttpResponseMessage = New HttpResponseMessage(HttpStatusCode.OK) With {
    .Content = New PushStreamContent(Async Function(outStream, httpContent, context)
        Dim writer As StreamWriter = New StreamWriter(outStream)
        Await writer.WriteLineAsync("""Header 1"",""Header 2"",""Header 3""")
        For Each item In returnItems
            Await writer.WriteLineAsync("""" & item.Col1.ToString & """,=""" & item.Col2.ToString & """,=""" & item.Col3.ToString & """")
            Await writer.FlushAsync()
        Next
        outputStream.Close()
    End Function)}

result.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("text/csv")
result.Content.Headers.ContentDisposition = New _
  Headers.ContentDispositionHeaderValue("attachment") With {.FileName = "MyCSV.csv"}

Return result