Загрузка больших файлов MVC заканчивается нехваткой памяти

.Net 4.5.1 — MVC5 — EF6

Требование состоит в том, чтобы разрешить загрузку больших файлов (‹200 МБ). У меня есть ViewModel с HttpPostedFileBase. Я установил входной поток этого в свойство DB Entity NonMapped Stream. Который затем отправляется в репозиторий, где я сохраняю копию потока в SQLFileStream. Это все работает.

Однако... При отладке примерно после ~ 4 больших загрузок я получаю исключение System.OutOfMemory. Я вижу, что HttpRawUploadedContent продолжает расти и сохраняет в памяти больше не используемые PostedFiles. Что я делаю не так? Как я могу заставить эти вещи избавиться? Есть ли способ лучше? Любое руководство приветствуется.

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
}

Несопоставленное свойство в базе данных FileEnitity

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

Метод добавления FileRepository.cs

    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;
    }

Снимок экрана памяти введите здесь описание изображения


person Tony    schedule 15.05.2015    source источник
comment
Вам нужно найти другое решение. Веб-серверы не предназначены для обработки такого размера загрузки. Честно говоря, HTTP как протокол не предназначен для обработки такого размера загрузки.   -  person Chris Pratt    schedule 15.05.2015
comment
У вас есть requestLengthDiskThreshold в web.config?   -  person Kadir    schedule 15.05.2015
comment
Да, он установлен на 204800   -  person Tony    schedule 15.05.2015
comment
@Chris Pratt Чем больше я думаю, тем больше меня раздражает первый ответ. Это не только плохая информация, но и вообще не касается вопроса. Я хотел бы прочитать в спецификации Http, где говорится, что он предназначен только для загрузки небольших файлов. Кроме того, какое отношение Http вообще имеет к этому вопросу? Какой глупый ответ. Требуется загружать большие файлы и хранить их в базе данных. Вместо того, чтобы публиковать свое дезинформированное мнение, как если бы оно было фактом, и заявлять, что нужно найти другое решение; как насчет предложить другой способ, который соответствует требованиям.   -  person Tony    schedule 15.05.2015
comment
Помните, что HTTP как спецификация была создана еще в начале 90-х, еще до того, как появилась такая вещь, как сеть. HTTP предназначен для быстрой и эффективной короткой связи. Он никогда не разрабатывался и не предназначался для использования в массовых расширенных сеансах связи с загрузкой данных объемом в сотни мегабайт. Это просто факт. Какое это имеет отношение к чему-либо? Это чертов протокол, который вы пытаетесь использовать для загрузки файлов. Как вы думаете, почему существует протокол FTP?   -  person Chris Pratt    schedule 15.05.2015
comment
Что касается таких сайтов, как YouTube. Ну, они должны использовать то, что они должны использовать. К лучшему или к худшему, это означает HTTP. Но есть одно различие между ними и вами — это огромные суммы денег, которые нужно бросить на решение проблемы. Они могут покупать серверы с терабайтами ОЗУ, большими супербыстрыми жесткими дисками, хранилищем CDN и т. д. Они также часто используют каналы прямого подключения, чтобы не было обмена между их центром обработки данных и крупным поставщиком каналов, таким как Level3. Это делает возможным многое в протоколе, который не был предназначен для него.   -  person Chris Pratt    schedule 15.05.2015
comment
Вы по-прежнему не предоставили доказательств того, что Http не предназначен для загрузки больших файлов. Тот факт, что вы даже упомянули Ftp, показывает мне, что вы не понимаете проблемы. Ftp абсолютно ничего не выигрывает в этом сценарии. Если бы я хотел, чтобы пользователь мог возобновить загрузку, я бы использовал Ftp. Используемый Freaking Protocol не имеет ничего общего с вопросом или проблемой. Проблема связана с проблемой памяти либо в .Net, IIS, либо в моем коде. Я говорю о загрузке ~ 4 файлов размером менее 200 МБ; YouTube имеет миллионы загрузок до 2 ГБ. Очевидно, Freaking Protocol может удовлетворить мои потребности.   -  person Tony    schedule 15.05.2015
comment
@ kad1r Спасибо за ваш ответ, вы направили меня в правильном направлении. Если вы опубликуете ответ, я приму его.   -  person Tony    schedule 16.05.2015
comment
Я рад, что это помогло вам исправить.   -  person Kadir    schedule 16.05.2015


Ответы (1)


Следует отдать должное @kad1r, поскольку он указал мне правильное направление. (т.е. не HTTP)

Оказывается, я не понял, что на самом деле делает requestLengthDiskThreshold.

RequestLengthDiskThreshold должен быть меньше значения MaxRequestLength и указывает, в какой точке или «пороге» запрос начнет прозрачно буферизоваться на диск.

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

При увеличении этого значения IIS сохраняет больше запросов в памяти, а не на диске.

person Tony    schedule 15.05.2015