2

I have a big JSON object which I need to pass to the view displayed in web browser. Since I can not have a Controller with an Action to return this JSON object, I thought to add the JSON object in the Razor view.

  1. @Html.Hidden("fileContent", fileContent);

  2. <textarea style="display:none"> @fileContent </textarea>

None of the above works as the ways I expected and gives me,

Exception of type 'System.OutOfMemoryException' was thrown.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.

Yes, I agreed that's better to restructure the flow in another way (may be as Mediator suggest or have an action to return the JSON object.)

  1. Is that a limitation of MVC, the maximum size we can have for a MVC view?
  2. Is this because of the IIS Express configuration?
  3. Any other way to overcome this issue? Or the best way to pass a large object to the client browser.

Thank you for your time. Any help would be highly appreciated.

EDIT

Controller

var file = System.IO.File.ReadAllText(HttpContext.Server.MapPath("~/content/data.csv"));
ViewData.Add("file", file);
return View();

Stack trace

[OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.] System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount) +163 System.Text.StringBuilder.Append(Char* value, Int32 valueCount) +82
System.Text.StringBuilder.AppendHelper(String value) +31
System.Text.StringBuilder.Append(String value) +186
System.IO.StringWriter.Write(String value) +30
System.Web.WebPages.WebPageBase.Write(Object value) +87

13
  • What is fileContent? And what is the point of sending it to the view and then sending it back again unchanged? Commented Feb 8, 2017 at 5:37
  • There are many factors causing OutOfMemoryException, e.g. StringBuilder overflow or lack of memory allocation for certain thread. Check controller code to make sure resource allocations are handled properly. Commented Feb 8, 2017 at 6:00
  • @StephenMuecke the fileContent is a JSON string. I convert that string into JSON object in the client side java script. This JSON object will use to render the page. Commented Feb 8, 2017 at 6:15
  • 1
    How big is data.csv? Commented Feb 8, 2017 at 7:04
  • 1
    The problem appears to be that Razor can't allocate enough contiguous memory to create a 1.5 MB array (probably 3 MB due to UTF-16, and probably 4 MB due to the expanding of the StringBuilder's internal array). This is an awful little amount of memory to throw this exception. Try using a string array of lines instead and see if that resolves the problem. Commented Feb 8, 2017 at 8:55

1 Answer 1

-1

Depending on your CSV file size, better to use ReadLines than ReadAllText like below:

var sb = new StringBuilder();
sb.Capacity = 16; // default, adjust it to less number as you wish

foreach (String line in System.IO.File.ReadLines(HttpContext.Server.MapPath("~/content/data.csv")))
{
    sb.Append(line);    
}

ViewData.Add("file", sb.ToString());

ReadLines returns IEnumerable<String> that reads a file line by line (one line at a time), hence it is suitable for certain files which potentially consuming huge memory space when stored as single large string.

However, if file contents are extremely large, consider using StreamReader instead of StringBuilder which requires contiguous array size and depends on heap fragmentation:

using (var sr = new System.IO.StreamReader(HttpContext.Server.MapPath("~/content/data.csv")))
{
     String line;
     while ((line = sr.ReadLine()) != null)
     {
         // combine source strings here
     }
}

Note that each character requires 2 bytes, and strings are array of characters, thus there should be contiguous arrays which affects performance and size during generating objects in memory. Hence, optimizing garbage collector functionality with GC.Collect() method may helpful after dealing with huge amount of objects requiring immediate cleanup.

Related references:

interesting OutOfMemoryException with StringBuilder

MSDN: System.Text.StringBuilder

MSDN: System.IO.StreamReader

Eric Lippert: Out Of Memory” Does Not Refer to Physical Memory

Sign up to request clarification or add additional context in comments.

6 Comments

The reading is not the problem, the writing onto the view is.
Thank you for passing valuable tips. File reads successfully to the variable. (into ViewData), error occurs once it try to render the DOM element with that value.
Not sure if it works, but my idea was to split JSON strings by each line into several hidden fields after executing ReadLines which passed array of strings e.g. @for (int i = 0; i < file.Length; i++) { @Html.Hidden("fileContent" + i, file[i]); } due to possible limitations in hidden field value rendered by HTML.
@TetsuyaYamamoto It is working. It should because Razor doesn't use the lengthy value. But again I have to combine those strings into one in the java script which also can cause the lag. Seems that's is a limitation of the Razor engine, isn't it?
I think it isn't limitation from Razor engine, it may comes from HTML specification which limits value in hidden field at certain amount of characters. I will edit the answer above after all things were confirmed.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.