# .NET文件上傳服務設計 # 前言 在b站學習了一個後端小項目,然後發現這個文件上傳設計還挺不錯,來實現講解一下。 項目結構如下: ![image](https://img2023.cnblogs.com/blog/3091176/202306/3091176-20230615155702089 ...
.NET文件上傳服務設計
前言
在b站學習了一個後端小項目,然後發現這個文件上傳設計還挺不錯,來實現講解一下。
項目結構如下:
基於策略+工廠模式實現文件上傳服務
枚舉
在Model層創建即可
public enum UploadMode
{
Local = 1, //本地上傳
Qiniu = 2 //七牛雲上傳
}
第一步:創建文件策略和工廠
在Service層中創建FileStrategy文件夾,在該文件夾下分別創建Strategy
、QiNiuStrategy
、LocalStrategy
、FileFactory
、FileContext
類
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介面
這裡需要安裝Http
Nuget包,不然沒有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層安裝Qiniu
Nuget包
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));
}
}
測試
返回的圖片路徑可以根據自己的需求進行更改。
去bin目錄查看圖片是否上傳成功
總結
上述內容就是對於文件上傳服務的設計,有其他文件上傳需求,比如分片斷點上傳、上傳到其他的服務商,只需要新增策略,完成邏輯代碼即可,還是很方便的一種文件上傳設計。