首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >上传和下载ASP.NET核心3.1中的大型文件?

上传和下载ASP.NET核心3.1中的大型文件?
EN

Stack Overflow用户
提问于 2020-06-21 17:43:47
回答 5查看 55.5K关注 0票数 41

我正在使用干净的架构处理一个ASP.NET Core3.1API项目,我有以下类库(层):

  • 基础设施(保安和上传助手等)
  • 持久性(DA层)
  • 域(域模型)
  • 应用程序(用例-业务逻辑)
  • API (API项目作为我的启动项目)

我希望能够将大型文件上传到服务器(比如2Gb的文件大小甚至更多),并在此之后下载它们,并且希望这样做--,而不会出现内存溢出和其他问题。

任何帮助都将不胜感激。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2020-06-24 12:39:27

如果您有那么大的文件,请不要在代码中使用byte[]MemoryStream。仅在下载/上载文件时才对流进行操作。

你有几个选择:

  • 如果您同时控制客户端和服务器,请考虑使用类似于tus的工具。.NET有客户端实现和服务器实现,这可能是最简单和最健壮的选项。
  • 如果您使用HttpClient上传大型文件,只需使用StreamContent类发送它们。同样,不要使用MemoryStream作为源,而是使用其他类似于FileStream的东西。
  • 如果您使用HttpClient下载大型文件,那么指定HttpCompletionOptions (例如var response = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead) )是很重要的。否则,HttpClient将在内存中缓冲整个响应。然后,您可以通过var stream = response.Content.ReadAsStreamAsync()将响应文件作为流处理。

ASP.NET核心特定建议:

  • 如果希望通过HTTP接收文件,则需要增加请求大小限制:[RequestSizeLimit(10L * 1024L * 1024L * 1024L)][RequestFormLimits(MultipartBodyLengthLimit = 10L * 1024L * 1024L * 1024L)]。此外,还需要禁用表单值绑定,否则整个请求将被缓冲到内存中:
代码语言:javascript
复制
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
   public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
   {
       public void OnResourceExecuting(ResourceExecutingContext context)
       {
           var factories = context.ValueProviderFactories;
           factories.RemoveType<FormValueProviderFactory>();
           factories.RemoveType<FormFileValueProviderFactory>();
           factories.RemoveType<JQueryFormValueProviderFactory>();
       }

       public void OnResourceExecuted(ResourceExecutedContext context)
       {
       }
   }
  • 若要从控制器返回文件,只需通过File方法返回它,该方法接受流:return File(stream, mimeType, fileName);

示例控制器如下所示(缺少的助手类请参见https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1 ):

代码语言:javascript
复制
private const MaxFileSize = 10L * 1024L * 1024L * 1024L; // 10GB, adjust to your need

[DisableFormValueModelBinding]
[RequestSizeLimit(MaxFileSize)]
[RequestFormLimits(MultipartBodyLengthLimit = MaxFileSize)]
public async Task ReceiveFile()
{
    if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
        throw new BadRequestException("Not a multipart request");

    var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType));
    var reader = new MultipartReader(boundary, Request.Body);

    // note: this is for a single file, you could also process multiple files
    var section = await reader.ReadNextSectionAsync();

    if (section == null)
        throw new BadRequestException("No sections in multipart defined");

    if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition))
        throw new BadRequestException("No content disposition in multipart defined");

    var fileName = contentDisposition.FileNameStar.ToString();
    if (string.IsNullOrEmpty(fileName))
    {
        fileName = contentDisposition.FileName.ToString();
    }

    if (string.IsNullOrEmpty(fileName))
        throw new BadRequestException("No filename defined.");

    using var fileStream = section.Body;
    await SendFileSomewhere(fileStream);
}

// This should probably not be inside the controller class
private async Task SendFileSomewhere(Stream stream)
{
    using var request = new HttpRequestMessage()
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri("YOUR_DESTINATION_URI"),
        Content = new StreamContent(stream),
    };
    using var response = await _httpClient.SendAsync(request);
    // TODO check response status etc.
}

在本例中,我们将整个文件流到另一个服务中。在某些情况下,最好将文件暂时保存到磁盘。

票数 95
EN

Stack Overflow用户

发布于 2021-05-24 17:24:51

有时问题是我们使用Nginx作为部署在ubuntu/Linux环境中的asp.net核心应用程序的前端代理。在我的例子中,这正是我试图在docker或.net核心端调试的地方,但是实际的解决方案是将Nginx配置配置为

client_max_body_size 50M;

此行可以添加到Nginx配置的位置或服务器设置中,以供您面临问题的站点使用。

可能对某人有帮助。

票数 2
EN

Stack Overflow用户

发布于 2021-04-22 03:37:14

我发现这篇文章很有用- https://www.tugberkugurlu.com/archive/efficiently-streaming-large-http-responses-with-httpclient

下面是下载大型文件所需代码的版本:

代码语言:javascript
复制
static public async Task HttpDownloadFileAsync(HttpClient httpClient, string url, string fileToWriteTo) {
  using HttpResponseMessage response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
  using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync(); 
  using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create); 
  await streamToReadFrom.CopyToAsync(streamToWriteTo);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62502286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档