C#使用Ionic.Zip打包下载重复触发时报相同键已添加错误如何解决?
问题原因
- 你使用的DotNetZip库的
ZipFile.AddFile()方法会以「压缩包内目标路径+文件名」作为唯一Key存入内部字典,同一个Key不允许重复添加。触发错误的核心原因是同一个Zip实例被多次添加了目标路径完全相同的文件,结合你的复现条件,常见诱因有2种:- 你的数据源
dt被多请求共享:如果dt被声明为静态变量、或者存储在Session/全局缓存中被复用,多次点击触发的并发请求会往同一个dt中追加重复的文件记录,导致单次请求循环时同一个文件路径被重复添加到新创建的Zip实例中。 - 同批文件本身存在重名:如果选中的多个源文件文件名完全相同,且都被添加到压缩包的
files目录下,也会触发Key重复,不过该场景首次下载就会报错,不符合你的复现条件,可以优先排查上一种情况。
- 你的数据源
解决方案
- 第一步:修复数据源复用问题
禁止使用静态变量存储单次请求的查询结果dt,每次接收下载请求时都重新查询生成独立的dt实例,避免多请求数据互相污染。 - 第二步:添加文件前做重复校验
在调用AddFile前先判断压缩包内是否已存在相同路径的文件,避免重复添加,同时优化响应结束逻辑避免资源清理异常,代码修改如下:using (ZipFile zip = new ZipFile()) { foreach (DataRow row in dt.Rows) { // 此处保留你原来的业务逻辑代码 string fileName = Path.GetFileName(filePath); string entryPath = Path.Combine("files", fileName); // 已存在则跳过,也可以根据需求重命名后添加(比如加(1)后缀) if (!zip.ContainsEntry(entryPath)) { zip.AddFile(filePath, "files"); } } Response.Clear(); Response.AddHeader("Content-Disposition", "attachment; filename=DownloadedFile.zip"); Response.ContentType = "application/zip"; zip.Save(Response.OutputStream); // 替换Response.End()避免线程中止异常导致的资源清理异常 Response.Flush(); HttpContext.Current.ApplicationInstance.CompleteRequest(); } - 第三步:前端防重复提交
用户点击下载按钮后立即将按钮置为禁用状态,直到下载请求处理完成后再恢复,从入口避免短时间内多次重复请求。
内容的提问来源于stack exchange,提问作者Unknown
相关产品推荐
相关产品推荐

