ASP.NET Core 中 HttpResponse.TransmitFile 的替代方法

问题描述 投票:0回答:2

由于我想实现从 ASP.NET Core 后端下载大尺寸文件(> 4GB),许多文章指出 .NET Framework 中的

HttpResponse.TransmitFile
可以实现我的目标。

但是,

HttpResponse.TransmitFile
在.NET Core中似乎不再可用。

有谁知道 .NET Core 中

HttpResponse.TransmitFile
的替代品是什么?我无法告诉你我是多么感谢你的相关回答。

asp.net asp.net-core .net-core httpresponse downloadfileasync
2个回答
0
投票

我怀疑真正的问题不是找到

TransmitFile
的替代方案(它是
return File(path)
return File(stream)
,而是处理请求范围,以便客户端可以分块下载大文件,如果中断可以重试。

幸运的是,自 ASP.NET Core 2.1 以来可用的 ControllerBase.File 方法和 Minimal API(以及其他)中使用的 Results.File 方法都已经支持这一点。范围处理默认关闭,但可以通过将

true
传递给
enableRangeProcessing
参数来启用,例如:

public class VideoController : Controller
{
    [HttpGet, Route("videos/video.mp4")]
    public IActionResult Index()
    {
        return File("d:\Videos\video.mp4", "video/mp4", true);
    }
}

更好的是,静态文件提供程序还支持开箱即用的范围(和响应压缩)。如果大文件位于特定文件夹中,您可以使用以下命令提供它们:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider("path\to\large\files"),  
    RequestPath = "/Videos"
});

如果您想在自己的操作中使用 响应压缩,您必须在 Web 服务器上启用它或通过响应压缩中间件显式启用它:

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
});

var app = builder.Build();

app.UseResponseCompression();

从那时起,客户端就需要检索特定的块并重试它们。下载实用程序通常会分块下载大文件,并自动重试失败的部分。 Khalid Abuhakmeh 在一篇简短的博客文章中描述了该过程以及它如何与 ASP.NET Core 一起工作。

在 C# 中,HttpClient 可以请求文件的特定块,甚至可以使用

Range

 标头同时下载它们,例如:

var req = new HttpRequestMessage { RequestUri = new Uri( url ) }; req.Headers.Range = new RangeHeaderValue( 0, 999 ); var resp = await client.SendAsync(req); if (resp.IsSuccessStatusCode) { using var tempFile=File.Create("chunk.001"); await resp.Content.CopyToAsync(tempFile); }
    

-1
投票
您可以使用下面的示例来实现该需求。有关更多详细信息,您可以查看博客

ASP.NET Core 上的 Streaming Zip

private static HttpClient Client { get; } = new HttpClient(); [HttpGet] public async Task<FileStreamResult> Get() { // get your stream var stream = await Client.GetStreamAsync("https://raw.githubusercontent.com/StephenClearyExamples/AsyncDynamicZip/master/README.md"); return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain")) { FileDownloadName = "README.md" }; }
对于拉链:

private static HttpClient Client { get; } = new HttpClient(); [HttpGet] public IActionResult Get() { var filenamesAndUrls = new Dictionary<string, string> { { "README.md", "https://raw.githubusercontent.com/StephenClearyExamples/AsyncDynamicZip/master/README.md" }, { ".gitignore", "https://raw.githubusercontent.com/StephenClearyExamples/AsyncDynamicZip/master/.gitignore" }, }; return new FileCallbackResult(new MediaTypeHeaderValue("application/octet-stream"), async (outputStream, _) => { using (var zipArchive = new ZipArchive(new WriteOnlyStreamWrapper(outputStream), ZipArchiveMode.Create)) { foreach (var kvp in filenamesAndUrls) { var zipEntry = zipArchive.CreateEntry(kvp.Key); using (var zipStream = zipEntry.Open()) using (var stream = await Client.GetStreamAsync(kvp.Value)) await stream.CopyToAsync(zipStream); } } }) { FileDownloadName = "MyZipfile.zip" }; }

该解决方案与我们之前的非核心解决方案具有相同的优点:

    所有 I/O 都是异步的。 I/O 上任何线程都不会被阻塞。
  1. zip 文件不保存在内存中。它直接流式传输到客户端,并进行即时压缩。
  2. 对于大文件,甚至单个文件也不会完全读入内存。每个文件都单独即时压缩。
© www.soinside.com 2019 - 2024. All rights reserved.