Возврат файла в asp net core 3.0 вызывает утечку памяти

У меня есть такой способ.

[HttpGet("view/{fileId}/{width}/{height}/{name}")]
public async Task<FileStreamResult> View(Guid fileId, int width, int height, string name)
{
    var fileInfo = await _fileViewer.GetImageInfo(fileId, width, height);
    FileStream f = new FileStream(fileInfo.FilePath, FileMode.Open);
    return File(f, fileInfo.MimeType);
}

Которая просто возвращает преобразованное изображение в браузер. Оно работает. Но насколько я могу судить, это утечка памяти.

FileStream f никогда не утилизируется.

Я вижу, что память моих серверов медленно расходуется.

Если я добавлю туда оператор using, я получаю сообщение об ошибке, что поток закрыт, т.е. оператор using закрывается до того, как файл будет возвращен пользователю.

Как это сделать правильно?

ОБНОВЛЕНИЕ 1. Этот:

using (FileStream f = new FileStream(fileInfo.FilePath, FileMode.Open))
{
    return File(f, fileInfo.MimeType);
}

дает

System.ObjectDisposedException: невозможно получить доступ к удаленному объекту. Имя объекта: «Нет доступа к закрытому файлу.».


person JensB    schedule 08.02.2020    source источник
comment
Можете ли вы включить код, который вы реализовали для своего оператора using? Очевидно, что правильный ответ - либо явно вызвать Dispose(), либо заключить ваш FileStream в оператор using, но нам нужно будет оценить, почему ваш оператор using не работал.   -  person Jeremy Caney    schedule 09.02.2020
comment
вы можете попробовать скопировать свой поток в массив байтов и использовать другую перегрузку метода File. в этом случае вы можете закрыть поток до завершения запроса.   -  person Yegor Androsov    schedule 09.02.2020
comment
@pwrigshihanomoronimo Я пробовал это, и он тоже работает, но я бы предпочел передать файл пользователю в потоковом режиме. Возможно, я ошибаюсь, но я думаю, что таким образом он не загружается в оперативную память.   -  person JensB    schedule 09.02.2020
comment
Если ваша гипотеза верна, то у всех, кто использует эту конструкцию в своем приложении, будут утечки памяти. Поскольку это не так, я думаю, вы обнаружите, что утечка памяти происходит не из-за этого метода.   -  person Ian Kemp    schedule 09.02.2020
comment
@IanKemp, возможно, вы правы, я надеюсь, что ошибаюсь, и это просто ленивый сборщик мусора. Но барана поедает очень много. Остальная часть кода просто выполняет запрос к базе данных и возвращает путь. Нет никаких других потоков или чего-то подобного. И я использую тот же метод для других вещей, которые постоянно не едят барана.   -  person JensB    schedule 09.02.2020
comment
Это здесь очищается Stream, который вы передаете этому File методу.   -  person Kirk Larkin    schedule 09.02.2020


Ответы (1)


Я предлагаю вам использовать файловые провайдеры Asp.net Core вместо того, чтобы вручную читать файлы с помощью system.IO. https://docs.microsoft.com/en-us/aspnet/core/fundamentals/file-providers?view=aspnetcore-3.1

но если вы не хотите использовать внедрение зависимостей и вставлять fileProvider в свой контроллер, этот трюк должен сработать для вас:

var fileInfo = await _fileViewer.GetImageInfo(fileId, width, height);
var fileName = Path.GetFileName(fileInfo.FilePath);
IFileProvider x = new PhysicalFileProvider(Path.GetDirectoryName(fileInfo.FilePath));
IFileInfo fi =  x.GetFileInfo(fileName);
 // you can use your mime type as second argumant. (fileInfo.MimeType)
return File(fi.CreateReadStream(), MediaTypeNames.Application.Octet , fileName);
person AliReza    schedule 08.02.2020