使用MVC的StringWriter内存不足,可以增加内存吗?

时间:2013-10-17 15:09:28

标签: xml asp.net-mvc out-of-memory

我必须创建一个大型的XML电子表格,它现在似乎已经达到了它可以一次性应对的门槛。

我不确定如何拆分它,所以想知道是否有办法为内部目的增加内存分配?

导致错误的代码如下:

private string RenderViewToString()
{
    using (var writer = new StringWriter())
    {
        var view = ViewEngines.Engines.FindView(_context, _viewName, null).View as RazorView;
        var viewDataDictionary = new ViewDataDictionary<TModel>(_model);
        var viewCtx = new ViewContext(_context, view, viewDataDictionary, new TempDataDictionary(), writer);
        viewCtx.View.Render(viewCtx, writer);
        return writer.ToString();
    }
}

当用户决定从可能的数据组合中下载所有数据时,它落在Render()上,在数据丰富之前,此文件将大约55mb转换为Excel文档。现在列已加倍,渲染编写器的代码行正在倒下。

viewCtx.View.Render(viewCtx, writer);

有没有人有解决方法或者知道如何将相关数据拆分为可管理的块而不重新编码?

它从视图模型中获取数据,并且本身在多个表中占用1到数万行,并且用户在单个Excel下载中需要所有这些行,这会导致问题。

字符串出现在这段代码中:

    protected override void WriteFile(HttpResponseBase response)
    {
        response.Write(RenderViewToString());

    }

但是它是否需要返回字符串的整个问题是无关紧要的,因为它从来没有因为ViewContext.View.Render(ViewContext,TextWriter)摔倒,所以有没有办法渲染ViewContext由于相对较小的文件(60+ MB)导致问题而没有掉头的东西?

我试图允许在web.config中使用大文件(一位同事建议)但是没有用。

目前ViewContext太大而无法渲染,所以我只需要找到一种方法来渲染它而不使用内置的,任何想法?

-----编辑-----

非常感谢Joe,我修改了你的代码,因为我没有IIS设置使用HttpContext标头,但是下面的代码可以解决这个问题:

        HttpContext.Current.Response.Clear();
        using (var writer = new StreamWriter(HttpContext.Current.Response.OutputStream))
        {
            var view = ViewEngines.Engines.FindView(_context, _viewName, null).View
                as RazorView;
            var viewDataDictionary = new ViewDataDictionary<TModel>(_model);
            var viewCtx = new ViewContext(_context,
                view, viewDataDictionary, new TempDataDictionary(), writer);
            viewCtx.View.Render(viewCtx, writer);
        }
        return null;

现在生成70MB文件没问题。

1 个答案:

答案 0 :(得分:1)

您正在将视图输出写入字符串,然后将其写入响应。您可能想要做的是跳过中间人,并将视图直接写入响应。由于Render方法接受任何TextWriter,因此您可以将Response.OutputStream传递到StreamWriter,而不只是写入普通字符串。

类似于:

System.Web.HttpContext.Current.Response.Clear();
System.Web.HttpContext.Current.Response.Headers["content-disposition"] = 
    "attachment;filename=somefile.txt"; // or whatever
System.Web.HttpContext.Current.Response.Headers["content-type"] =
    "text/plain"; // or whatever
using (var writer = new StreamWriter(System.Web.HttpContext.Current.Response.OutputStream))
{
    var view = ViewEngines.Engines.FindView(_context, _viewName, null).View
        as RazorView;
    var viewDataDictionary = new ViewDataDictionary<Foo>(_model);
    var viewCtx = new ViewContext(_context, 
        view, viewDataDictionary, new TempDataDictionary(), writer);
    viewCtx.View.Render(viewCtx, writer);
}
return null;