2017-11-29 2 views
2

私は、約20の列のわずか200万レコードを超えるテーブルを持つデータベースを持っています。ユーザーはデータベースにクエリを実行し、返されるレコードの数を制限して、レコードセットが1〜200万になるようにすることができます。未知のサイズのCSVをメモリからストリーミングする正しい方法

表情報であるため、データを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 

私は、このようなReturning binary file from controller in ASP.NET Web APIような質問にStackOverflowの回答に読んだが、これらのファイルメモリからディスクに格納されていないから、ウェブ応答をストリーミングして、すべての契約。

+0

Response.OutputStreamに書き込み、メモリストリームをスキップできます。 – dwilliss

+0

あなたがリンクした例のPushStreamContentを使うことができます。MemorySteamをPushStreamContentのstreamパラメータで置き換え、 'stream.Position = 0'文を省略するだけです。 (ここではC#を使用してよろしいですか?) 'result.Content = new PushStreamContent((stream、httpContent、transportContext)=> {var writer = new StreamWriter(stream); \ *コード残り* writer.Flush(); stream.Close();})m "text/csv"); ' – ckuri

答えて

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 
関連する問題