2014-09-25 88 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