我正在使用干净的体系结构开发ASP.NET Core 3.1 API项目,并且具有以下类库(层):
我希望能够将较大的文件上传到服务器(例如2Gb甚至更大的文件大小),然后再下载,并希望以后不会出现内存溢出和其他所有问题。
任何帮助,将不胜感激。
如果文件太大,则不要使用byte[]
或MemoryStream
在代码中使用。如果您下载/上传文件,则仅在流上操作。
您有两种选择:
StreamContent
该类发送它们。再说一次,不要使用MemoryStream
as作为源,而是使用其他源FileStream
。var response = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead)
。否则,HttpClient会将整个响应缓冲在内存中。然后,您可以通过将响应文件作为流处理var stream = response.Content.ReadAsStreamAsync()
。ASP.NET Core特定建议:
[RequestSizeLimit(10L * 1024L * 1024L * 1024L)]
和[RequestFormLimits(MultipartBodyLengthLimit = 10L * 1024L * 1024L * 1024L)]
。另外,您需要禁用表单值绑定,否则整个请求将被缓冲到内存中: [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://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1):
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.
}
在此示例中,我们将整个文件流式传输到另一个服务。在某些情况下,最好将文件临时保存到磁盘。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句