Search code examples
c#asp.net-mvcmemoryfile-uploadsqlfilestream

MVC Large File Uploads Running Out of Memory


.Net 4.5.1 - MVC5 - EF6

The requirement is to allow large file uploads(<200MB). I have a ViewModel with HttpPostedFileBase. I set the Input Stream of that to a DB Entity NonMapped Stream Property. Which is then sent to the Repository where I save the Copy the Stream to a SQLFileStream. This all works.

However... When debugging after about ~4 large uploads I receive a System.OutOfMemory Exception. I can see that HttpRawUploadedContent is continuing to grow and is keeping the no longer used PostedFiles in memory. What am I doing wrong? How can I get these things to dispose? Is there a better way? Any guidance is appreciated.

AttachmentViewModel.cs

public class AttachmentViewModel
{
    #region Public Properties

    public int Id { get; set; }

    public string FileName { get; set; }

    [MaxFileSize]
    public HttpPostedFileBase PostedFile { get; set; }

    
    #endregion Public Properties
}

Non Mapped Property on Database FileEnitity

    [NotMapped]
    public Stream PostedStream {  get; set; }

FileRepository.cs Add Method

    public override T Add(T entity)
    {
        base.Add(entity);

        //Save to generate ID
        _ctx.SaveChanges();

        using (var tx = new TransactionScope())
        {
            try
            {
                var id = entity.Id;

                var rowData =
                    _ctx.Database.SqlQuery<FileStreamData>(FileRowSelect, new SqlParameter("id", id))
                        .First();

                using (var dest = new SqlFileStream(rowData.Path, rowData.Transaction, FileAccess.Write))
                {
                    //Copy the posted stream to the SQLFileStream
                    entity.PostedStream.CopyTo(dest);
                }

                tx.Complete();
            }
            catch
            {
                //Error Uploading Stream Revert
                base.Remove(entity);
                _ctx.SaveChanges();
                throw;
            }
        }
        return entity;
    }

Screen Shot of Memory enter image description here


Solution

  • The credit should go to @kad1r as he pointed me in the right direction. (i.e.: not Http)

    Turns out I did not understand the what requestLengthDiskThreshold actually does.

    The RequestLengthDiskThreshold should be less than the MaxRequestLength value and indicates at what point or 'threashold' that the request will begin to be buffered transparently onto disk.

    http://forums.asp.net/t/1680176.aspx?httpRuntime+maxRequestLength+vs+requestLengthDiskThreshold+

    By increasing this value IIS stores more of the request in memory rather than on disk.