Hello,
I have a big zip file in the server (5GB). I am trying to send the file to the front end so that the user can download it.
return new RemoteStreamContent(zipFileStream, zipFileName, FileTypes.Zip.ContentType);
This approach works for moderate files, however gives an error for big files.
2025-05-22 12:07:54.247 +03:00 [ERR] Stream was too long.
System.IO.IOException: Stream was too long.
at System.IO.MemoryStream.WriteAsync(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
--- End of stack trace from previous location ---
at System.IO.Stream.<CopyToAsync>g__Core|27_0(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
at System.IO.Strategies.BufferedFileStreamStrategy.CopyToAsyncCore(Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
at Volo.Abp.AspNetCore.Mvc.ContentFormatters.RemoteStreamContentOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|28_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Volo.Abp.AspNetCore.Serilog.AbpSerilogMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at IPS.IPSHttpApiHostModule.<>c.<<OnApplicationInitialization>b__12_0>d.MoveNext() in C:\eld-vm-01-b1\_work\27\s\src\IPS.HttpApi.Host\IPSHttpApiHostModule.cs:line 359
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Volo.Abp.AspNetCore.Security.Claims.AbpDynamicClaimsMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.Uow.AbpUnitOfWorkMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
What should be the approach for big files?
Thank you.
13 Answer(s)
-
0
Hi, ABP’s
RemoteStreamContent
is great for lightweight files or when you want to abstract things but it’s not designed for very large files. It attempts to copy the stream into an in-memory buffer (MemoryStream), which crashes for files >2GB or causes heavy memory usage.So, for large files, instead, you can use
FileStream
(see https://stackoverflow.com/a/39890811/10477283) andFileStreamResult
. -
0
-
0
hi
I am trying to send the file to the front end so that the user can download it.
Please share your full app service code.
Thanks.
-
0
public async Task< FileStreamResult > ExportAsync(ExportDto input) { var contents = new Dictionary<string, byte[]>(); var discardedContents = new Dictionary<string, byte[]>(); FillMuyCompressionItems(ref contents, ref discardedContents); FillMlCompressionItems(ref contents, ref discardedContents); FillAkbCompressionItems(ref contents, ref discardedContents); FillCkCompressionItems(ref contents, ref discardedContents); var zipFileName = "EXPORT.zip"; var mainZipFileStream = new FileStream(Path.Join(Path.GetTempPath(), zipFileName), FileMode.Create, FileAccess.ReadWrite); using (var zipArchive = new ZipArchive(mainZipFileStream, ZipArchiveMode.Create, true)) { for (var i = 0; i < contents.Count; i++) { var item = contents.ElementAt(i); var originalFileStream = new FileStream(Path.Join(Path.GetTempPath(), item.Key), FileMode.Create, FileAccess.ReadWrite); await originalFileStream.WriteAsync(item.Value); originalFileStream.Seek(0, SeekOrigin.Begin); var zipEntry = zipArchive.CreateEntry(item.Key, CompressionLevel.Fastest); await using(var zipEntryStream = zipEntry.Open()) await using (originalFileStream) { await originalFileStream.CopyToAsync(zipEntryStream); } } } mainZipFileStream.Seek(0, SeekOrigin.Begin); return new FileStreamResult(mainZipFileStream, FileTypes.Zip.ContentType); }
-
0
hi
Can you also share the code of
IRemoteStreamContent
version? Thanks -
0
public async Task< IRemoteStreamContent > ExportAsync(ExportDto input) { var contents = new Dictionary<string, byte[]>(); var discardedContents = new Dictionary<string, byte[]>(); FillMuyCompressionItems(ref contents, ref discardedContents); FillMlCompressionItems(ref contents, ref discardedContents); FillAkbCompressionItems(ref contents, ref discardedContents); FillCkCompressionItems(ref contents, ref discardedContents); var zipFileName = "EXPORT.zip"; var mainZipFileStream = new FileStream(Path.Join(Path.GetTempPath(), zipFileName), FileMode.Create, FileAccess.ReadWrite); using (var zipArchive = new ZipArchive(mainZipFileStream, ZipArchiveMode.Create, true)) { for (var i = 0; i < contents.Count; i++) { var item = contents.ElementAt(i); using var originalFileStream = new MemoryStream(item.Value); var zipEntry = zipArchive.CreateEntry(item.Key, CompressionLevel.Fastest); await using var zipEntryStream = zipEntry.Open(); await originalFileStream.CopyToAsync(zipEntryStream); } } mainZipFileStream.Seek(0, SeekOrigin.Begin); return new RemoteStreamContent(mainZipFileStream, zipFileName, FileTypes.Zip.ContentType); }
-
0
Thanks. Do you have
app.UseAbpStudioLink();
in yourIPSHttpApiHostModule.cs
?If so, Please remove it and use
IRemoteStreamContent
again. -
0
It worked perfectly, thank you so much!
Though, I really wonder what is the corelation between AbpStudioLink and IRemoteStreamContent if it is not a secret? :) What makes it does not work?
-
0
hi
AbpStudioLink will use MemoryStream; We will fix it in the next version.
Thanks.
-
0
Oh I see!
Does this mean that it is better to add
app.UseAbpStudioLink();
again after the next version? Or let it be removed like this? -
0
hi
You can use it in the next version. remove it now. ; )
-
0
Got it!
-
0
Great