You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 2.0 MVC多文件上传至Azure Blob进度显示问题咨询

.NET Core 2.0 MVC 文件上传进度条实现问题解答

我完全理解你在实现这个功能时的头疼——官方文档在这块确实太简略了,尤其是要同时处理双阶段上传进度+多文件的场景,踩坑是难免的。下面针对你的四个问题逐一解答:


问题1:是否需要两个进度条分别对应客户端到服务器、服务器到Azure的上传?

完全正确!这是两个完全独立的传输阶段:

  • 第一阶段是客户端→服务器:用户浏览器把文件传到你的.NET Core服务器,进度反映的是文件从用户本地到你服务器的传输状态
  • 第二阶段是服务器→Azure Blob:服务器拿到文件后再上传至Azure存储,这又是一个独立的传输过程
    因为两个阶段的速度可能差异很大(比如用户网络慢,或者服务器到Azure的带宽受限),分开展示两个进度能让用户清晰了解上传的整体状态,体验会好很多。

问题2:如何在前端展示每个文件的上传进度?

不建议用AJAX轮询服务器的List[i],更高效的方式是结合前端XHR/Fetch进度监听+服务器端实时推送:

  1. 客户端→服务器的进度:前端用FormData封装多文件,通过XMLHttpRequest发送请求,监听progress事件就能实时获取每个文件的上传进度,直接更新对应文件的第一个进度条。示例代码大概是这样:
const formData = new FormData();
// 假设fileInput是你的文件选择控件
fileInput.files.forEach(file => formData.append('videoFile', file));

const xhr = new XMLHttpRequest();
xhr.open('POST', '/YourController/Upload');
xhr.upload.addEventListener('progress', (e) => {
  if (e.lengthComputable) {
    const percent = (e.loaded / e.total) * 100;
    // 更新对应文件的客户端上传进度条
    updateClientProgress(file.name, percent);
  }
});
xhr.send(formData);
  1. 服务器→Azure的进度:这个阶段的进度在服务器端,前端没法直接监听,最好用SignalR(.NET Core 2.0支持)做实时推送:
    • 服务器端在处理Azure上传时,把进度通过SignalR推送给前端
    • 前端连接SignalR Hub,接收进度消息后更新对应文件的第二个进度条

如果暂时不想用SignalR,也可以把每个文件的Azure上传进度存在服务器的IMemoryCache里,前端定时AJAX请求接口获取进度,但这种轮询方式效率低,延迟高,体验不如实时推送。


问题3:while循环读取字节时,文件是否已在服务器缓存?

没错!当你调用videoFile[i].OpenReadStream()的时候,文件已经被ASP.NET Core框架缓存到服务器了——默认情况下,小于64KB的文件会存在内存里,大于这个值的会存在服务器的临时目录中。你代码里的while循环其实是在读取已经缓存到服务器的文件内容,而不是实时从客户端接收数据。

这也是为什么你没法通过这个循环获取客户端到服务器的上传进度——这个循环处理的是已经上传完成(或部分完成)的缓存内容,不是接收上传的过程。


问题4:如何利用Azure的IProgress实现在进度变化时返回结果?当前Console.WriteLine无法生效。

Console.WriteLine在ASP.NET Core服务器环境(比如IIS、Azure App Service)下确实没用,因为服务器的控制台输出前端根本看不到。要把进度传递给前端,得用实时通信机制,这里推荐用SignalR:

  1. 先给项目添加SignalR的NuGet包(.NET Core 2.0对应Microsoft.AspNetCore.SignalR包),然后配置SignalR服务
  2. 创建一个Hub类,用来向前端发送进度消息:
public class UploadProgressHub : Hub { }
  1. 在你的Blob服务类中注入IHubContext<UploadProgressHub>,然后修改UploadBlobAsync的进度回调:
private readonly IHubContext<UploadProgressHub> _hubContext;

// 构造函数注入
public YourBlobService(IHubContext<UploadProgressHub> hubContext)
{
    _hubContext = hubContext;
}

public async Task<bool> UploadBlobAsync(string blobContainer, string blobName, IFormFile file, string connectionId)
{
    CloudBlobContainer container = await GetContainerAsync(blobContainer);
    CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
    CancellationToken cancellationToken = new CancellationToken();
    
    IProgress<StorageProgress> progressHandler = new Progress<StorageProgress>(progress =>
    {
        // 计算进度百分比
        var percent = (double)progress.BytesTransferred / file.Length * 100;
        // 通过SignalR把进度推送给指定客户端
        _hubContext.Clients.Client(connectionId).SendAsync("ReceiveAzureProgress", blobName, percent);
    });
    
    using (var filestream = file.OpenReadStream())
    {
        await blob.UploadFromStreamAsync(filestream, default(AccessCondition), default(BlobRequestOptions), default(OperationContext), progressHandler, cancellationToken);
    }
    return true;
}
  1. 前端连接SignalR Hub,监听ReceiveAzureProgress事件,更新对应文件的Azure上传进度条:
const connection = new signalR.HubConnectionBuilder()
    .withUrl("/uploadProgressHub")
    .build();

connection.on("ReceiveAzureProgress", (fileName, percent) => {
    updateAzureProgress(fileName, percent);
});

connection.start().catch(err => console.error(err.toString()));

如果暂时不想用SignalR,也可以把进度存在服务器的IMemoryCache里(用文件名或唯一标识当key),前端定时AJAX请求接口获取,但这种方式体验会差很多。


内容的提问来源于stack exchange,提问作者Ian Gleeson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:58:42