ASP.NET Core向Azure Blob传大文件遇OutOfMemoryException求助
解决ASP.NET Core上传大文件到Azure Blob时的OutOfMemoryException问题
这个错误很典型——默认情况下,ASP.NET Core处理multipart/form-data表单上传时,会把整个文件内容缓冲到内存或者服务器临时磁盘中,当你上传256MB的文件时,加上应用本身的内存占用,很容易就超过WebApp的3.5GB内存限制,触发OutOfMemoryException。
下面是一步步的解决方案,核心思路是流式分块上传,让文件内容不经过完整加载到内存,直接流到Azure Blob存储:
1. 先配置ASP.NET Core允许大文件上传
首先要调整应用的请求大小限制,不然Kestrel或者中间件会直接拒绝大文件请求。在Program.cs里添加以下配置:
builder.Services.Configure<FormOptions>(options => { // 设置单个文件的最大大小(这里设为500MB,可根据需求调整) options.MultipartBodyLengthLimit = 524288000; // 设置整个表单的最大大小 options.ValueLengthLimit = 524288000; }); // 配置Kestrel的请求限制 builder.WebHost.ConfigureKestrel(options => { options.Limits.MaxRequestBodySize = 524288000; // 500MB });
2. 使用Azure Blob的流式分块上传API
不要用传统的把文件读进byte[]的方式,而是直接用文件流配合Azure.Storage.Blobs的UploadAsync方法,它支持自动分块上传,而且会流式处理内容,不会把整个文件加载到内存。
控制器示例代码
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Microsoft.AspNetCore.Mvc; public class UploadFilesController : Controller { private readonly BlobServiceClient _blobServiceClient; // 依赖注入BlobServiceClient(建议从配置中获取连接字符串) public UploadFilesController(BlobServiceClient blobServiceClient) { _blobServiceClient = blobServiceClient; } [HttpPost] public async Task<IActionResult> Post() { if (!Request.HasFormContentType) { return BadRequest("请求不是multipart/form-data类型"); } var formFile = Request.Form.Files.FirstOrDefault(); if (formFile == null || formFile.Length == 0) { return BadRequest("没有选择要上传的文件"); } try { // 获取容器客户端(替换为你的容器名称) var containerClient = _blobServiceClient.GetBlobContainerClient("your-container-name"); await containerClient.CreateIfNotExistsAsync(); // 获取blob客户端,用文件名作为blob名称(可根据需求修改命名规则) var blobClient = containerClient.GetBlobClient(formFile.FileName); // 配置上传选项,启用流式分块 var uploadOptions = new BlobUploadOptions { ParallelTransferOptions = new ParallelTransferOptions { // 设置分块大小(建议在4MB到100MB之间,这里用32MB) BlockSize = 33554432, // 32 * 1024 * 1024 // 设置并发上传的分块数,根据服务器资源调整 MaxConcurrency = 2 }, // 如果需要覆盖已存在的blob,设置为true Overwrite = true }; // 直接用文件流上传,该方法会自动处理分块,不会把整个文件加载到内存 using var fileStream = formFile.OpenReadStream(); await blobClient.UploadAsync(fileStream, uploadOptions); return Ok($"文件 {formFile.FileName} 上传成功"); } catch (Exception ex) { // 可添加日志记录逻辑 return StatusCode(500, $"上传失败:{ex.Message}"); } } }
3. 额外优化建议
- 坚持异步操作:确保所有Azure Blob的操作都使用异步方法(比如
UploadAsync),避免阻塞线程导致资源浪费。 - 灵活调整分块参数:如果WebApp网络带宽较好,可适当增大
BlockSize(但不要超过Azure Blob单个分块的100MB上限);如果带宽一般,减小分块大小并降低MaxConcurrency,避免占用过多网络资源。 - 监控内存指标:可以在Azure Portal中查看WebApp的内存使用情况,确认大文件上传时内存占用处于合理范围。
这样调整后,你的应用就可以流式处理大文件上传,不会把整个文件加载到内存,也就避免了OutOfMemoryException的问题。
内容的提问来源于stack exchange,提问作者Artem Danchenko
相关产品推荐
相关产品推荐

