当前位置: 首页 > news >正文

C#在.NET MVC中如何设计大附件上传的进度监控界面?

开发者日记:2023年X月X日 星期X 长沙 晴

项目背景
今日正式启动客户的大文件传输系统项目,需求明确:支持20G文件/文件夹上传下载、跨平台(Windows/macOS/Linux)、全浏览器兼容(含IE8)、断点续传、保留文件夹层级结构。后端使用**.NET Core**(而非PHP),数据库改为SQL Server,存储仍用阿里云OSS,前端为Vue3 CLI + WebUploader/H5。客户强调高频文件夹上传场景,需极致优化用户体验。免费开源代码和7*24支持的压力依旧,但技术栈调整带来新挑战。


技术选型与调整

  1. 前端框架

    • Vue3 CLI:维持组件化开发,但需适配IE8的Polyfill(如babel-polyfill)。
    • WebUploader:核心上传组件,需深度定制文件夹解析逻辑。
    • H5 File API:现代浏览器备用方案,IE8回退到Flash上传。
  2. 后端架构

    • .NET Core:替代PHP,利用IFormFile处理分片,System.Data.SqlClient操作SQL Server。
    • SQL Server:存储文件元数据(路径、分片状态、用户ID)。
  3. 核心难点升级

    • 高频文件夹上传:需优化递归解析性能,避免前端卡顿。
    • 断点续传稳定性:SQL Server事务保证分片记录一致性。
    • IE8兼容性:Flash上传需处理跨域问题(crossdomain.xml)。

前端代码优化(Vue3 + WebUploader)

1. 强化文件夹上传逻辑
// src/components/FolderUploader.vueimport{ref,onMounted}from'vue';importWebUploaderfrom'webuploader';import'webuploader/dist/webuploader.css';exportdefault{setup(){constuploader=ref(null);constfolderTree=ref([]);// 存储文件夹层级结构onMounted(()=>{// 动态加载Flash(IE8兼容)if(!WebUploader.Uploader.support('HTML5')){WebUploader.Uploader.register({name:'flash',fn:()=>'/assets/Uploader.swf'});}uploader.value=newWebUploader.Uploader({swf:'/assets/Uploader.swf',server:'/api/upload',pick:'#folderPicker',chunked:true,chunkSize:4*1024*1024,// 4MB分片formData:{fileId:'',isDir:false,relativePath:''// 关键:记录文件相对路径}});// 监听文件夹选择(需配合input[directory])document.getElementById('folderInput').addEventListener('change',(e)=>{constitems=e.target.files;if(items){parseFolder(items);// 递归解析文件夹}});});// 递归解析文件夹(兼容现代浏览器)constparseFolder=(items)=>{consttree=[];for(leti=0;i<items.length;i++){constfile=items[i];constpath=file.webkitRelativePath||file.name;// 相对路径constsegments=path.split('/');// 构建树形结构letcurrentLevel=tree;segments.slice(0,-1).forEach(segment=>{letdir=currentLevel.find(item=>item.name===segment);if(!dir){dir={name:segment,type:'directory',children:[]};currentLevel.push(dir);}currentLevel=dir.children;});// 添加文件节点currentLevel.push({name:segments.pop(),type:'file',file:file,relativePath:path});}folderTree.value=tree;uploadFolder(tree);};// 上传文件夹内容constuploadFolder=(tree)=>{tree.forEach(node=>{if(node.type==='directory'){uploadFolder(node.children);// 递归上传子目录}else{constformData=uploader.value.option('formData');formData.relativePath=node.relativePath;uploader.value.addFile(node.file,node.relativePath);}});};return{uploader,folderTree};}};
2. IE8兼容性处理

后端代码实现(.NET Core + SQL Server)

1. 分片上传接口
// Controllers/UploadController.csusingMicrosoft.AspNetCore.Mvc;usingSystem.Data.SqlClient;usingSystem.IO;[ApiController][Route("api/upload")]publicclassUploadController:ControllerBase{privatereadonlyIConfiguration_config;publicUploadController(IConfigurationconfig)=>_config=config;[HttpPost]publicasyncTaskUpload([FromForm]UploadModelmodel){varfileId=model.FileId??Guid.NewGuid().ToString();vartempDir=Path.Combine("/tmp/uploads",fileId);Directory.CreateDirectory(tempDir);// 保存分片varchunkPath=Path.Combine(tempDir,$"chunk_{model.ChunkIndex}");using(varstream=newFileStream(chunkPath,FileMode.Create)){awaitmodel.File.CopyToAsync(stream);}// 记录分片状态到SQL Serverusing(varconn=newSqlConnection(_config.GetConnectionString("Default"))){awaitconn.OpenAsync();varcmd=newSqlCommand(@"MERGE INTO UploadProgress AS target USING (VALUES (@fileId, @chunkIndex, @totalChunks)) AS source (FileId, ChunkIndex, TotalChunks) ON target.FileId = source.FileId AND target.ChunkIndex = source.ChunkIndex WHEN NOT MATCHED THEN INSERT (FileId, ChunkIndex, TotalChunks, UploadedAt) VALUES (source.FileId, source.ChunkIndex, source.TotalChunks, GETDATE());",conn);cmd.Parameters.AddWithValue("@fileId",fileId);cmd.Parameters.AddWithValue("@chunkIndex",model.ChunkIndex);cmd.Parameters.AddWithValue("@totalChunks",model.TotalChunks);awaitcmd.ExecuteNonQueryAsync();}// 如果是最后一块,合并并上传OSSif(model.ChunkIndex==model.TotalChunks-1){varfinalPath=Path.Combine(tempDir,"final_file");using(varoutput=System.IO.File.Create(finalPath)){for(inti=0;i<model.TotalChunks;i++){varchunk=System.IO.File.ReadAllBytes(Path.Combine(tempDir,$"chunk_{i}"));awaitoutput.WriteAsync(chunk,0,chunk.Length);}}// 上传OSS(需引入阿里云OSS SDK)varclient=newOSSClient("endpoint","accessKey","secretKey");awaitclient.PutObjectAsync("bucket-name",$"uploads/{fileId}",finalPath);// 清理临时文件Directory.Delete(tempDir,true);}returnOk(new{success=true,fileId});}}publicclassUploadModel{publicIFormFileFile{get;set;}publicstringFileId{get;set;}publicintChunkIndex{get;set;}publicintTotalChunks{get;set;}publicstringRelativePath{get;set;}// 文件夹层级路径}
2. SQL Server表结构
CREATETABLEUploadProgress(IdINTIDENTITY(1,1)PRIMARYKEY,FileId NVARCHAR(64)NOTNULL,ChunkIndexINTNOTNULL,TotalChunksINTNOTNULL,UploadedAt DATETIME2DEFAULTGETDATE(),UNIQUE(FileId,ChunkIndex));

断点续传实现

1. 前端恢复逻辑
// 检查未完成上传constcheckResume=async(fileId)=>{constres=awaitfetch(`/api/upload/progress?fileId=${fileId}`);constdata=awaitres.json();if(data.completedChunks<data.totalChunks){uploader.value.option('formData',{fileId,chunk:data.completedChunks});uploader.value.upload();}};// 本地存储fileId(即使浏览器关闭)window.addEventListener('beforeunload',()=>{if(uploader.value.getFiles().length>0){localStorage.setItem('lastUploadId',uploader.value.option('formData').fileId);}});
2. 后端进度查询
[HttpGet("progress")]publicasyncTaskGetProgress(stringfileId){using(varconn=newSqlConnection(_config.GetConnectionString("Default"))){awaitconn.OpenAsync();varcmd=newSqlCommand("SELECT COUNT(*) AS Completed FROM UploadProgress WHERE FileId = @fileId",conn);cmd.Parameters.AddWithValue("@fileId",fileId);varcount=(int)awaitcmd.ExecuteScalarAsync();returnOk(new{completedChunks=count});}}

今日总结

  • 进展:完成文件夹层级解析和.NET Core分片上传逻辑,IE8兼容性方案验证通过。
  • 问题
    1. WebUploader在IE8下对大文件夹性能较差,需优化DOM操作。
    2. SQL Server事务需加强,避免分片记录残留。
  • 明日计划
    1. 实现OSS分片上传(避免本地合并临时文件)。
    2. 编写完整的错误处理和日志系统。

求助:若有熟悉.NET Core文件处理或SQL Server优化的高手,欢迎加入QQ群374992201指导!代码将完全开源回馈社区。


(注:实际项目需补充安全校验、OSS直传和性能监控代码。)

设置框架

安装.NET Framework 4.7.2
https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472
框架选择4.7.2

添加3rd引用

编译项目

NOSQL

NOSQL无需任何配置可直接访问页面进行测试

SQL

使用IIS
大文件上传测试推荐使用IIS以获取更高性能。

使用IIS Express

小文件上传测试可以使用IIS Express

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


相关参考:
文件保存位置,

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

批量下载

支持文件批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

下载完整示例

下载完整示例

http://www.jsqmd.com/news/118874/

相关文章:

  • 2025年长春管道疏通联系方式汇总:全市专业服务官方的联系渠道与高效合作指引 - 品牌推荐
  • 事倍功半是蠢蛋70 命名问题
  • Excalidraw移动端体验优化策略
  • Excalidraw性能调优:大规模图形渲染优化
  • Windows系统文件datime.dll缺失或损坏问题 下载修复
  • 2025年南京管道疏通联系方式汇总:全市专业服务官方联系渠道与高效合作指引 - 品牌推荐
  • 适配周期缩短60%!Open-AutoGLM预训练模型高效调优方法论,一线大厂已验证
  • 2025年长春管道疏通联系方式汇总:全市专业服务官方联系渠道与高效合作指引 - 品牌推荐
  • Excalidraw本地化部署+GPU加速,性能提升300%
  • 莫比乌斯基本定理证明
  • Excalidraw自动对齐与布局功能使用技巧
  • learning_gem5 part1_05 gem5 v24.1:使用 gem5 标准库安装脚本
  • Windows系统文件davhlpr.dll损坏或缺失 下载修复
  • Open-AutoGLM广域网访问配置全攻略(专家级实战经验曝光)
  • 从耗时10小时到40分钟:Open-AutoGLM微调效率逆袭之路
  • 【专家亲授】Open-AutoGLM迁移学习加速方案:训练时间缩短70%的实操路径
  • 2025年合肥管道疏通联系方式汇总:全市专业服务商官方联系方式与高效合作指引 - 品牌推荐
  • Windows系统文件daxctle.ocx缺失或损坏问题 下载修复
  • Open-AutoGLM系统版本兼容优化实战(专家级调优秘籍)
  • 【优化充电】基于位置和价格激励的电动汽车智能充电研究附Matlab代码
  • FCKEditor组件支持Word图片上传转存矢量格式
  • 不再局限于局域网!Open-AutoGLM广域网访问配置的5个关键步骤
  • 2025成都火锅口碑榜,排队也要吃!特色美食/烧菜火锅/老火锅/社区火锅/火锅/美食/火锅店火锅哪家好吃口碑推荐榜 - 品牌推荐师
  • Windows系统文件dbghelp.dll损坏或丢失 免费下载修复
  • 为什么90%的团队在Open-AutoGLM适配阶段失败?:深度剖析底层对齐机制缺失
  • 2025年合肥管道疏通联系方式汇总:全市专业服务商官方联系通道与高效合作指引 - 品牌推荐
  • 跨平台AI模型部署难题全解析,Open-AutoGLM适配方案深度拆解
  • Excalidraw安全机制解读:数据加密与权限控制
  • Windows系统文件dbnmpntw.dll损坏或丢失 免费下载修复
  • 如何在5分钟内完成Open-AutoGLM安全认证加固?(附配置模板)