
1. ASP.NET大文件上传系统开发全记录作为一名长期从事企业级文件传输系统开发的工程师我最近完成了一个颇具挑战性的项目——基于ASP.NET WebForm的大文件上传系统支持20GB以上文件传输、文件夹上传保留层级结构、断点续传和加密传输等核心功能。这个项目让我积累了丰富的实战经验今天就来详细分享整个开发过程和技术细节。1.1 项目背景与核心需求客户是一家半导体制造企业需要在芯片设计部门与生产车间之间传输大量的设计文件单个文件经常超过20GB。原有FTP传输方式存在以下痛点大文件传输不稳定经常中断后需要重新上传无法保持设计文件的文件夹层级结构缺乏有效的传输加密机制无法兼容车间老旧的IE8浏览器基于这些痛点我们确定了以下核心需求大文件处理能力支持20GB以上文件稳定传输文件夹上传保持完整的目录结构断点续传支持浏览器关闭后继续上传加密传输采用AES/SM4加密算法兼容性要求支持IE8及所有现代浏览器技术栈限制必须使用ASP.NET WebFormC#后端1.2 技术选型与架构设计经过充分调研我们确定了以下技术方案前端技术栈基础上传库WebUploader支持分片上传和IE8兼容加密方案Web Crypto API crypto-js polyfill进度管理自定义实现基于文件MD5的断点续传文件夹上传修改WebUploader源码支持webkitRelativePath后端技术栈上传处理ASP.NET WebForm通用处理程序(.ashx)文件存储阿里云OSS私有云存储数据库SQL Server 2016加密处理.NET Framework内置AES/SM4算法系统架构图[前端] → [分片加密] → [ASP.NET WebForm] → [临时存储] → [合并加密] → [阿里云OSS] ↑ ↓ [WebUploader] [SQL Server状态记录]2. 核心功能实现细节2.1 大文件分片上传机制大文件上传的核心在于分片处理。我们设置每个分片大小为5MB通过以下公式计算总分片数分片数量 CEILING(文件大小 / 分片大小)前端关键代码实现// WebUploader初始化配置 uploader WebUploader.create({ chunked: true, chunkSize: 5 * 1024 * 1024, // 5MB分片 chunkRetry: 3, // 分片失败重试次数 threads: 3 // 并发上传数 });后端接收处理逻辑string tempDir Server.MapPath($~/App_Data/UploadTemp/{userId}/{fileMd5}); if (!Directory.Exists(tempDir)) Directory.CreateDirectory(tempDir); string tempFilePath Path.Combine(tempDir, chunk.ToString()); file.SaveAs(tempFilePath);注意事项分片大小需要权衡网络环境和服务器性能通常2-10MB为宜临时目录应按用户ID和文件MD5分级存储避免冲突分片命名建议使用序号而非随机名便于后续合并2.2 文件夹上传与结构保持实现文件夹上传的关键是获取文件的相对路径信息。我们修改了WebUploader源码添加了webkitRelativePath的支持// 在WebUploader的_addFiles方法中添加 file.webkitRelativePath originalFile.webkitRelativePath || ;后端存储时重建目录结构string relativePath context.Request.Form[relativePath]; string ossKey $uploads/{userId}/{DateTime.Now:yyyyMMdd}/{relativePath}; // 确保OSS目录存在 CreateOssDirectory(Path.GetDirectoryName(ossKey));2.3 断点续传实现方案我们采用文件MD5分片记录的方式实现断点续传前端计算MD5uploader.md5File(file) .then(function(md5) { file.md5 md5; checkResumeInfo(file); });后端记录分片状态CREATE TABLE UploadChunks ( UserId NVARCHAR(50) NOT NULL, FileMd5 NVARCHAR(32) NOT NULL, Chunk INT NOT NULL, Status NVARCHAR(20) DEFAULT Pending, UNIQUE (UserId, FileMd5, Chunk) );续传查询接口public Listint GetUploadedChunks(string userId, string fileMd5) { // 查询已上传分片序号列表 return db.Queryint(SELECT Chunk FROM UploadChunks WHERE UserIduserId AND FileMd5fileMd5 AND StatusUploaded, new { userId, fileMd5 }).ToList(); }2.4 加密传输实现采用前端分片加密后端完整加密的双重保障前端加密AESfunction encryptChunk(chunkData, key) { var iv CryptoJS.lib.WordArray.random(16); var encrypted CryptoJS.AES.encrypt(chunkData, key, { iv: iv }); return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64); }后端加密SM4using (SM4 sm4 new SM4()) { sm4.Key Encoding.UTF8.GetBytes(config.EncryptKey); sm4.IV new byte[16]; using (var encryptor sm4.CreateEncryptor()) using (FileStream fsOutput new FileStream(outputFile, FileMode.Create)) using (CryptoStream csEncrypt new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write)) { fsInput.CopyTo(csEncrypt); } }3. 性能优化关键点3.1 IIS服务器配置优化对于大文件上传必须调整IIS的以下参数web.configsystem.web httpRuntime maxRequestLength2147483647 executionTimeout3600 / /system.web system.webServer security requestFiltering requestLimits maxAllowedContentLength4294967295 / /requestFiltering /security /system.webServer3.2 数据库优化技巧分片记录批量插入// 使用表变量批量插入 DataTable chunkTable new DataTable(); // ...填充数据... using (SqlBulkCopy bulkCopy new SqlBulkCopy(connection)) { bulkCopy.DestinationTableName UploadChunks; bulkCopy.WriteToServer(chunkTable); }添加复合索引CREATE INDEX IX_UploadChunks_Main ON UploadChunks(UserId, FileMd5, Chunk) INCLUDE (Status, UploadTime);3.3 内存管理要点大文件处理必须注意内存释放// 使用using确保资源释放 using (FileStream fs new FileStream(tempFile, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 81920)) { // 处理逻辑 } // 显式调用GC大文件处理后 GC.Collect(); GC.WaitForPendingFinalizers();4. 兼容性处理方案4.1 IE8兼容实现对于IE8我们采用Flash后备方案WebUploader.create({ swf: /Content/Uploader.swf, // 其他配置... });4.2 现代浏览器特性检测渐进增强式功能检测// 检测文件夹上传支持 var isFolderSupported webkitdirectory in document.createElement(input); // 检测加密API支持 var isCryptoSupported window.crypto crypto.subtle;5. 实际部署经验5.1 阿里云OSS最佳实践分片上传优化var request new InitiateMultipartUploadRequest(bucketName, objectKey); var initResult client.InitiateMultipartUpload(request); // 上传分片 var uploadPartRequest new UploadPartRequest(bucketName, objectKey, initResult.UploadId, partNumber); uploadPartRequest.InputStream chunkStream; var uploadPartResult client.UploadPart(uploadPartRequest); // 完成上传 var completeRequest new CompleteMultipartUploadRequest(bucketName, objectKey, initResult.UploadId, partETags); client.CompleteMultipartUpload(completeRequest);权限控制设置var policy new PolicyStatement( ResourceFactory.CreateOssResource(bucketName, uploads/*), new[] { OssAction.OssGetObject }, Effect.Allow, new Principal(userId), new Condition[] { new IpAddressCondition( IpAddressCondition.IpAddressType.SourceIp, new[] { 192.168.1.0/24 }) });5.2 压力测试数据我们使用JMeter进行了压力测试阿里云ECS 4核8G配置并发用户数平均响应时间(ms)吞吐量(MB/s)错误率5032012.50%10048018.20%20062022.10.5%500120025.32.1%6. 常见问题与解决方案6.1 上传中断问题排查网络闪断实现心跳检测机制自动重连设置合理的超时时间建议120-300秒服务器超时// 增加IIS超时设置 httpRuntime executionTimeout3600 /6.2 内存溢出处理症状上传大文件时出现OutOfMemoryException解决方案确保使用流式处理而非全量读取设置合理的缓冲区大小通常8KB-1MB禁用IIS的缓冲system.webServer handlers add nameUploadHandler path*.ashx verb* typeYourHandler resourceTypeUnspecified preConditionintegratedMode / /handlers /system.webServer6.3 性能瓶颈分析通过性能分析发现主要瓶颈在MD5计算改用WebWorker后台计算磁盘IO使用SSD存储临时文件网络延迟启用HTTP/2和多路复用7. 完整部署流程7.1 服务器环境准备安装.NET Framework 4.7.2choco install dotnetfx --version4.7.2配置IIS应用程序池启用32位应用程序某些加密库需要设置专用模式内存限制4GB以上7.2 数据库部署执行表创建脚本见2.3节配置连接字符串connectionStrings add nameSQLServerConn connectionStringServer.;DatabaseFileUpload;Integrated SecurityTrue;Max Pool Size200; providerNameSystem.Data.SqlClient / /connectionStrings7.3 监控配置性能计数器监控ASP.NET Applications\Requests/SecProcess\Private BytesNetwork Interface\Bytes Total/sec日志记录策略log4net.Config.XmlConfigurator.Configure(); ILog logger LogManager.GetLogger(typeof(FileUpload)); logger.Info($Upload completed: {fileName});这个项目从技术调研到最终上线历时3个月期间遇到了无数挑战但最终的成果让客户非常满意。系统目前稳定运行日均处理超过2TB的设计文件传输。如果你正在开发类似系统希望这些经验能帮你少走弯路。