2014-09-25 48 views
1

通常我必須在我的應用程序中從數據庫創建csv導出文件。當我必須創建15 MB的導出文件時,我遇到了mvc問題,因爲要使用返回Content();,我需要在內存中創建包含所有數據的大字符串,並帶有頻繁的內存異常,所以我必須使用.aspx頁面,我可以在處理數據時使用Response.Write。如何在asp.net中支持大尺寸內容mvc

嘗試使用mvc的第二個問題是,如果我必須執行長時間處理,客戶端將看不到任何內容,直到我沒有完成闡述並開始發送它,並且經常認爲存在連接或服務器問題。

在處理mvc中的動作期間是否可以向內容發送數據,而不終止處理的完成?

+0

你可以用'Response.Write'在MVC太 – Rhumborl 2014-09-25 06:56:03

+0

你可以讓你的報表生成異步並通知用戶這是完成後(給他發電子郵件或顯示網址,在那裏他可以下載的文件)。 – 2014-09-25 07:18:20

回答

2

這是一段可解決此問題的代碼。但請注意,您可以使用Web API並創建CSV格式化程序(並禁用輸出緩衝)或直接使用pushtreamcontent。

對於MVC這裏是一個示例代碼,注意這個示例使用的是閉包,但您可以使用相同的IEnumerable。關鍵是讓評估懶惰,所以你不要在內存中創建整個字符串。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Threading; 
using System.Web; 
using System.Web.Mvc; 

namespace SampleApplication 
{ 
    public class HomeController : Controller 
    { 
     public ActionResult LargeCsv() 
     { 
      // TODO: Replace the func with real data access, or alternatively use an IQueryable/IEnumerable/IEnumerator implementation 
      // to access the data dynamically. 
      int i = 0; 
      Func<string> func =() => 
      { 
       while (i < 100) 
       { 
        i++; 
        return "Name" + i + ", " + i; 
       } 

       return null; 
      }; 

      return new CsvActionResult(func); 
     } 
    } 

    public class CsvActionResult : ActionResult 
    { 
     private readonly Func<string> _getNextCsvLine; 

     public CsvActionResult(Func<string> getNextCsvLine) 
     { 
      _getNextCsvLine = getNextCsvLine; 
     } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      context.HttpContext.Response.Headers.Add("Content-Type", "text/csv"); 

      context.HttpContext.Response.BufferOutput = false; 

      // StreamWriter has inherent buffering so this operation is reasonably performant, it 
      // is going to write buffers to the wire rather than each writeline. 
      using (StreamWriter sw = new StreamWriter(context.HttpContext.Response.OutputStream)) 
      { 
       string csvLine; 

       do 
       { 
        csvLine = _getNextCsvLine(); 
        sw.WriteLine(csvLine); 

       } while (csvLine != null); 
      } 
     } 
    } 
} 
0

我認爲你的應用程序邏輯有問題。我的意思是看着state machines讓你的應用程序進入不同的狀態。因此,在處理數據時,產生一個正在運行的任務,並在特定任務完成時通知。

您可以使用JS不時詢問服務器上的狀態,並且只有當任務完成後,才能發送它。

此外,請確保您在發送結果的大數據時(最終可能還會幫助您消耗內存)結束use compression