.NET MVC项目中,C#怎样实现文件夹的上传和下载功能?
作为上海某软件公司项目负责人,我最近正为“大文件传输功能集成”的事儿焦头烂额——公司现有产品覆盖政府、金融、能源等多个行业,客户对文件传输的需求从“能用”升级到了“好用、稳定、安全”。但市面上开源组件要么停更(如WebUploader)、要么功能残缺(不支持文件夹层级、断点续传不稳定),甚至遇到问题找不到技术支持,这让我们在和国企、央企客户谈合作时底气不足。
我们的核心需求(挑明不绕弯)
- 大文件传输能力:单文件100G+,文件夹保留层级(含10万+子文件场景),必须支持断点续传(刷新/关闭浏览器不丢进度)。
- 安全合规:加密传输(HTTPS+国密SM4/AES可选)、加密存储(密钥可配置),满足信创要求。
- 兼容与稳定:兼容IE8(Windows 7老机器)、主流浏览器;支持ASP.NET WebForm/.NET Core双技术栈;前端兼容vue2/vue3/React。
- 轻量集成:无缝嵌入现有产品,不改动原有业务流程和数据结构,避免“为了传文件把系统重构一遍”。
- 可维护性:供应商需提供长期技术支持(至少5年),附带央企/国企合作案例(合同、软著、信创认证等),降低决策风险。
我们的解决方案(从架构到代码)
经过3个月调研和内部测试,我们最终选择了“自研核心模块+成熟组件适配”的方案——基于分片上传、断点续传、加密存储三大核心技术,结合阿里云OSS的扩展能力,同时兼容旧系统和新框架。以下是关键实现细节:
一、架构设计(一张图说清)
二、关键技术点(附代码示例)
1. 前端:跨框架分片上传(兼容IE8+)
(基于原生JS封装,支持vue2/vue3/React,IE8用iframe fallback)
// utils/FileUploader.js(核心上传逻辑)
class FileUploader {
constructor(options) {
this.chunkSize = options.chunkSize || 5 * 1024 * 1024; // 5MB分片(100G分2万片)
this.file = options.file;
this.uploadId = options.uploadId; // 全局唯一上传ID(用于断点续传)
this.progressCallback = options.progressCallback;
this.onSuccess = options.onSuccess;
this.onError = options.onError;
}
}
// 使用示例(vue3组件)
export default {
methods: {
async handleFileUpload(file) {
const uploadId = uuidv4(); // 生成全局唯一ID
const uploader = new FileUploader({
file,
uploadId,
chunkSize: 5 * 1024 * 1024,
progressCallback: (progress) => {
this.progress = progress;
},
onSuccess: (res) => {
this.$message.success('上传成功!');
},
onError: (err) => {
this.$message.error(`上传失败:${err.msg}`);
}
});
await uploader.start();
}
}
};
2. 后端:ASP.NET WebForm/.NET Core 双栈支持(分片接收+加密存储)
(核心逻辑兼容新旧技术栈,SQL Server记录进度,阿里云OSS存储)
// ASP.NET WebForm 版本(UploadHandler.ashx)
public class UploadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/json";
var action = context.Request["action"];
switch (action)
{
case "check": // 检查已上传分片
CheckChunks(context);
break;
case "chunk": // 接收分片
UploadChunk(context);
break;
case "merge": // 合并分片
MergeChunks(context);
break;
}
}
private void CheckChunks(HttpContext context)
{
var uploadId = context.Request["uploadId"];
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["FileDB"].ConnectionString))
{
conn.Open();
var cmd = new SqlCommand("SELECT ChunkIndex FROM UploadProgress WHERE UploadId = @UploadId", conn);
cmd.Parameters.AddWithValue("@UploadId", uploadId);
var reader = cmd.ExecuteReader();
var uploadedChunks = new List();
while (reader.Read())
{
uploadedChunks.Add(reader.GetInt32(0));
}
context.Response.Write(JsonConvert.SerializeObject(new { uploadedChunks }));
}
}
private byte[] AesEncrypt(byte[] data, string key)
{
using (var aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = new byte[16]; // 实际需生成随机IV并存储
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
}
return ms.ToArray();
}
}
}
public bool IsReusable => false;
}
3. 下载功能:非打包+自动解密(防服务器崩溃)
(通过分片下载+前端合并,支持10万+文件场景)
// 前端下载逻辑(vue组件)
methods: {
async downloadFolder(folderId) {
// 获取文件夹结构(后端返回文件列表)
const { data } = await this.$http.get(`/api/folder/${folderId}/files`);
const files = data.files;
// 并发下载分片(控制并发数防服务器压力)
const concurrency = 5;
const downloadPromises = [];
for (let i = 0; i < files.length; i += concurrency) {
const batch = files.slice(i, i + concurrency);
batch.forEach(async (file) => {
const { data: chunks } = await this.$http.get(`/api/file/${file.id}/chunks`);
const decryptedChunks = [];
for (const chunk of chunks) {
const res = await this.$http.get(`/api/file/chunk/${chunk.id}`, {
responseType: 'blob'
});
decryptedChunks.push(await this.decryptChunk(res.data));
}
const mergedFile = await this.mergeChunks(decryptedChunks);
this.saveFile(mergedFile, file.name); // 保存到本地
});
}
},
// 解密分片(AES/SM4)
async decryptChunk(encryptedChunk) {
const key = await this.$http.get('/api/config/decryptKey'); // 从后端获取密钥
const iv = encryptedChunk.slice(0, 16); // 假设IV存储在分片前16字节
const data = encryptedChunk.slice(16);
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
return Buffer.concat([decipher.update(data), decipher.final()]);
},
// 合并分片
mergeChunks(chunks) {
return new Blob(chunks, { type: 'application/octet-stream' });
},
// 保存文件到本地
saveFile(blob, fileName) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
}
我们的优势与合作保障
- 技术兜底:提供7*24小时技术支持(电话/企业微信/现场驻场),核心问题2小时内响应。
- 资质齐全:可提供5+央企/国企项目案例(含合同原件、软著证书、信创认证、银行回单)。
- 灵活授权:按年授权(20万/年,不限项目数),支持私有部署/公有云/混合云,适配SQL Server/MySQL/Oracle。
- 无缝集成:提供Vue2/Vue3/React组件库,ASP.NET WebForm/.NET Core SDK,文档覆盖“开箱即用”到“深度定制”。
如果贵司也在寻找“稳定、安全、可维护”的大文件传输方案,欢迎联系(微信/电话:XXX-XXXX-XXXX),我们可以提供:
- 免费的“10G文件上传”demo环境(含IE8测试);
- 国企客户现场考察(某能源集团已落地);
- 定制化需求评审(3个工作日内输出方案)。
期待与您合作,一起搞定“大文件传输”这个技术硬骨头!
设置框架
安装.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

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试

相关参考:
文件保存位置,
效果预览
文件上传

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

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

下载完整示例
更多推荐
所有评论(0)