.NET 文件上传服务设计

  • .NET 文件上传服务设计已关闭评论
  • 244 次浏览
  • A+
所属分类:.NET技术
摘要

在b站学习了一个后端小项目,然后发现这个文件上传设计还挺不错,来实现讲解一下。


.NET文件上传服务设计

前言

在b站学习了一个后端小项目,然后发现这个文件上传设计还挺不错,来实现讲解一下。

项目结构如下:

.NET 文件上传服务设计

基于策略+工厂模式实现文件上传服务

枚举

在Model层创建即可

    public enum UploadMode     {         Local = 1, //本地上传         Qiniu = 2 //七牛云上传     } 

第一步:创建文件策略和工厂

在Service层中创建FileStrategy文件夹,在该文件夹下分别创建StrategyQiNiuStrategyLocalStrategyFileFactoryFileContext

Strategy 文件操作抽象类

/// <summary> /// 文件操作抽象类 /// </summary> public abstract class Strategy {     public abstract Task<string> Upload(List<IFormFile> formFiles); } 

LocalStrategy 本地策略

继承Strategy 文件操作抽象类并实现他里面的方法

后续要实现该方法

public class LocalStrategy:Strategy {     public override async Task<string> Upload(List<IFormFile> formFiles)     {         throw new NotImplementedException();     } } 

QiNiuStrategy 七牛云策略

同上

public class QiNiuStrategy:Strategy {     public override async Task<string> Upload(List<IFormFile> formFiles)     {         throw new NotImplementedException();     } } 

FileContext 上下文

在策略模式中通过上下文调用具体的策略

这里的好处就是我如果new LocalStrategy则是本地上传服务,如果是new QiNiuStrategy则是七牛云上传,详情看下方工厂的设计

/// <summary> /// 上下文,通过这个来调用具体的策略 /// </summary> public class FileContext {     private Strategy _strategy;     private List<IFormFile> _formFiles;      public FileContext(Strategy strategy, List<IFormFile> formFiles)     {         _formFiles = formFiles;         _strategy = strategy;     }      public async Task<string> ContextInterface()     {         return await _strategy.Upload(_formFiles);     } } 

FileFactory 工厂

通过工厂去负责对象的实例化

枚举的作用就来了,更据枚举去判断实例化那一个对象

/// <summary> /// 工厂类,负责对象的实例化 /// </summary> public class FileFactory {     public static Strategy CreateStrategy(UploadMode mode)     {         switch (mode)         {             case UploadMode.Qiniu:                 return new QiNiuStrategy();             case UploadMode.Local:                 return new LocalStrategy();             default:                 return new QiNiuStrategy();         }     } } 

第二步:对接服务层

在Interface接口层创建IFileService接口

这里需要安装HttpNuget包,不然没有IFormFile,我下的是Microsoft.AspNetCore.Http/2.2.2

public interface IFileService {     Task<string> Upload(List<IFormFile> files, UploadMode mode); } 

在Service层创建FileService类实现上面的接口

public class FileService:IFileService {     public async Task<string> Upload(List<IFormFile> files, UploadMode mode)     {         FileContext fileContext = new FileContext(FileFactory.CreateStrategy(mode), files);         return await fileContext.ContextInterface();     } } 

上述通过上下文调用具体的策略,通过工厂去创建具体的类,工厂更据传入的枚举作为参数(构造函数传参),通过上下文的ContextInterface就可以完成上传的逻辑了。

策略+工厂的好处就是,以后需要修改上传文件,只需要对策略进行更改和补充即可。意思就是新增一个上传策略,只需要创建一个策略类,然后去工厂类new一个就行了,不需要动Service层的东西。

本地上传功能实现

在本地策略类中实现上传方法

注意var filePath = $"{AppContext.BaseDirectory}/wwwroot";是将文件保存在bin目录下的wwwroot目录了

public class LocalStrategy:Strategy {     public override async Task<string> Upload(List<IFormFile> formFiles)     {         var res = await Task.Run(() =>         {             //存放多个文件路径             List<string> result = new List<string>();             foreach (var formFile in formFiles)             {                 if (formFile.Length > 0)                 {                     var filePath = $"{AppContext.BaseDirectory}/wwwroot";                     var fileName = $"/{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";                     if (!Directory.Exists(filePath))                     {                         Directory.CreateDirectory(filePath);                     }                     using (var stream = System.IO.File.Create(filePath + fileName))                     {                         formFile.CopyTo(stream);                     }                     result.Add(fileName);                 }             }             return string.Join(",", result);         });         return res;     } } 

七牛云上传功能实现

注册七牛云:https://www.qiniu.com/

从个人中心获取秘钥信息,安装SDK,编写上传逻辑

在Service层安装QiniuNuget包

ak、sk为七牛云的秘钥,在个人中心查看

public class QiNiuStrategy : Strategy {     public override async Task<string> Upload(List<IFormFile> formFiles)     {         //先上传到本地,才能上传到七牛云,上传完成后本地的文件可删除         var res = await Task.Run(() =>         {             Mac mac = new Mac("ak", "sk");             List<string> result = new List<string>();             foreach (var formFile in formFiles)             {                 if (formFile.Length > 0)                 {                     var filePath_temp = $"{AppContext.BaseDirectory}/Images_temp";                     var fileName = $"{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";                     if (!Directory.Exists(filePath_temp))                     {                         Directory.CreateDirectory(filePath_temp);                     }                      using (var stream = System.IO.File.Create($"{filePath_temp}/{fileName}"))                     {                         formFile.CopyTo(stream);                     }                      // 上传文件名                     string key = fileName;                     // 本地文件路径                     string filePath = $"{filePath_temp}/{fileName}";                     // 存储空间名                     string Bucket = "pl-static";                     // 设置上传策略                     PutPolicy putPolicy = new PutPolicy();                     // 设置要上传的目标空间                     putPolicy.Scope = Bucket;                     // 上传策略的过期时间(单位:秒)                     //putPolicy.SetExpires(3600);                     // 文件上传完毕后,在多少天后自动被删除                     //putPolicy.DeleteAfterDays = 1;                     // 生成上传token                     string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());                     Config config = new Config();                     // 设置上传区域                     config.Zone = Zone.ZONE_CN_East;                     // 设置 http 或者 https 上传                     config.UseHttps = true;                     config.UseCdnDomains = true;                     config.ChunkSize = ChunkUnit.U512K;                     // 表单上传                     FormUploader target = new FormUploader(config);                     HttpResult httpResult = target.UploadFile(filePath, key, token, null);                     result.Add(fileName);                     //删除备份文件夹                     Directory.Delete(filePath_temp, true);                 }             }              return string.Join(",", result);         });         return res;     } } 

Controller的实现

mode为1则会执行本地上传的逻辑代码,为2则会执行七牛云上传的服务代码。

[Route("api/[controller]/[action]")] [ApiController] public class FileController : ControllerBase {     private readonly IFileService _fileService;     public FileController(IFileService fileService)     {         _fileService = fileService;     }     /// <summary>     /// 上传文件     /// </summary>     /// <param name="file">文件对象</param>     /// <param name="mode">上传方式:本地或者七牛云</param>     /// <returns></returns>     [HttpPost]     public async Task<ApiResult> UploadFile(List<IFormFile> file, UploadMode mode)     {         return ResultHelper.Success(await _fileService.Upload(file, mode));     } } 

测试

.NET 文件上传服务设计

.NET 文件上传服务设计

返回的图片路径可以根据自己的需求进行更改。

去bin目录查看图片是否上传成功

.NET 文件上传服务设计

总结

上述内容就是对于文件上传服务的设计,有其他文件上传需求,比如分片断点上传、上传到其他的服务商,只需要新增策略,完成逻辑代码即可,还是很方便的一种文件上传设计。