.net 5 上傳文件到阿里雲的OSS 文件的上傳、下載 和文件的管理
1.先購買阿里雲的oss服務器
2.添加子用戶 會生成 AccessKeyId 和 AccessKeySecret 記錄下來
3.給當前子用戶添加管理阿里雲oss 的權限
//所需要用到的類
public class FileBaseRequest { /// <summary> /// 文件名稱 /// </summary> public string Name { get; set; } /// <summary> /// 文件大小 /// </summary> public long? Size { get; set; } /// <summary> /// 文件寬度 /// </summary> public int? Width { get; set; } /// <summary> /// 文件高度 /// </summary> public int? Height { get; set; } /// <summary> /// 文件類型 /// </summary> public string Type { get; set; } /// <summary> /// 文件唯一的Guid /// </summary> public string Guid { get; set; } /// <summary> /// 圖片形狀 /// </summary> public int ShapeTypeId { get; set; } /// <summary> /// url 地址 /// </summary> public string FilebaseUrl { get; set; } /// <summary> /// hash /// </summary> public string Hash { get; set; } }
public class DownFileInfo { public string Name { get; set; } public string Url { get; set; } }
public class ReturnBox { public int Code { get; set; } = 200; public object Data { get; set; } public string Message { get; set; } = "Success"; }
//連接的Helper 在使用前 在包管理工具中安裝阿里雲的包 Aliyun.OSS.Core, Version=2.13.0.0 按着自己的EF 或者 Core 都行
public class OSSHelper { #region Fields //https://zww1.oss-cn-shenzhen.aliyuncs.com/xxxxxx/filebase_dev/oringinal/123456dfsf.png private static OssClient _ossClient; private static AutoResetEvent _event; //賬號Id private const string AccessKeyId = "xxxxxxxxxx"; //賬號key private const string AccessKeySecret = "xxxxxxxxxx"; //oss所在的服務區域 private const string Endpoint = "https://oss-cn-shenzhen.aliyuncs.com"; //生成的圖片的路徑地址 private const string Branch = @"xxxxxx/filebase_dev/"; // 填寫Bucket名稱。 private const string BucketName = "zww1"; // 填寫Object完整路徑。Object完整路徑中不能包含Bucket名稱。 private const string objectName = "/xxxxxx/filebase_dev/"; // 填寫字符串。 private const string objectContent = ""; private const string ThumbSize = "350"; private const string DefaultSize = "750"; #endregion #region Constructors private OSSHelper() { _event = new AutoResetEvent(false); _ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret); } public static OSSHelper _() { return new OSSHelper(); } #endregion #region Method /// <summary> /// 通過文件流普通上傳 10 普通上傳 20 斷點續傳上傳 30進度條上傳 /// </summary> /// <returns></returns> public async Task<FileBaseRequest> HttpUpload(IFormFile file, int uploadtype = 10) { string nameStr = string.Empty; string name = file.FileName; if (!string.IsNullOrEmpty(name) && name.Contains('.')) { nameStr = name.Split('.')[0]; } string type = file.ContentType; string guid = Guid.NewGuid().ToString(); string filebaseUrl = string.Empty; string hash = ""; long? size = 0; int? width = 0; int? height = 0; int? shapeTypeId = 0; var strArr = type.Split('/'); using (var memoryStream = new MemoryStream()) { await file.CopyToAsync(memoryStream); size = file.Length; hash = ComputeMd5Hash(memoryStream); if (strArr[0].ToString() == "image") { using (Bitmap pic = new Bitmap(memoryStream)) { width = pic.Size.Width; height = pic.Size.Height; if (width > height) shapeTypeId = (int)ShapeType.Sideways; if (width < height) shapeTypeId = (int)ShapeType.vertical; if (width == height) shapeTypeId = (int)ShapeType.Square; } } if (strArr[0].ToString() == "video") { } byte[] oringinalBuffer, thumbBuffer, defaultBuffer; oringinalBuffer = memoryStream.ToArray(); thumbBuffer = GetThumbnail(oringinalBuffer, int.Parse(ThumbSize)); defaultBuffer = GetThumbnail(oringinalBuffer, int.Parse(DefaultSize)); switch (uploadtype) { case 10: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; _ossClient.PutObject(BucketName, filebaseUrl, requestContent); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { _ossClient.PutObject(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { _ossClient.PutObject(BucketName, $"{Branch}default/{guid}.jpg", requestContent); } break; case 20: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; var result = BreakPoint(BucketName, filebaseUrl, requestContent, nameStr); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { var result = BreakPoint(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent, nameStr); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { var result = BreakPoint(BucketName, $"{Branch}default/{guid}.jpg", requestContent, nameStr); } break; case 30: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; var result = PutObjectProgress(BucketName, filebaseUrl, requestContent); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { var result = PutObjectProgress(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { var result = PutObjectProgress(BucketName, $"{Branch}default/{guid}.jpg", requestContent); } break; default: break; } } return new FileBaseRequest { FilebaseUrl = $"https://zww1.oss-cn-shenzhen.aliyuncs.com/{filebaseUrl}", Guid = guid, Hash = hash, Height = height, Name = name, ShapeTypeId = (int)shapeTypeId, Size = size, Type = type, Width = width, }; } /// <summary> /// 單條下載 /// </summary> /// <returns></returns> public async Task<byte[]> HttpDownload(string url) { try { RestClient restClient = new RestClient(); var request = new RestRequest(url); var byteFile = restClient.DownloadData(request); return byteFile; } catch (Exception ex) { throw new AggregateException(ex.Message); } } /// <summary> /// 單條下載文件並轉流 /// </summary> /// <param name="fileName">文件路徑</param> /// <param name="isDelete">是否刪除臨時文件</param> /// <returns></returns> public Stream FileToStream(string fileName, bool isDelete = false, string url = null) { using (var client = new WebClient()) { string tempFile = Path.GetTempFileName(); client.DownloadFile(url, tempFile);//下載臨時文件 //Console.WriteLine("Using " + tempFile); //打開文件 FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); // 讀取文件的 byte[] byte[] bytes = new byte[fileStream.Length]; fileStream.Read(bytes, 0, bytes.Length); fileStream.Close(); // 把 byte[] 轉換成 Stream Stream stream = new MemoryStream(bytes); if (isDelete) { File.Delete(fileName);//刪除臨時文件 } return stream; } } /// <summary> /// 通過文件列表的Url地址下載文件 /// </summary> /// <param name="url">下載文件地址</param> /// <returns></returns> public async Task<Stream> HttpDownloadList(List<DownFileInfo> downFileInfos) { byte[] buffer = new byte[] { }; foreach (var item in downFileInfos) { RestClient restClient = new RestClient(); var request = new RestRequest(item.Url); buffer = restClient.DownloadData(request); } return new MemoryStream(buffer); } #endregion #region Utilities /// <summary> /// 進度條上傳方法 /// </summary> /// <param name="BucketName"></param> /// <param name="objectName"></param> /// <param name="stream"></param> /// <param name="CheckpointDir"></param> /// <returns></returns> public async Task<bool> PutObjectProgress(string bucketName, string objectName, Stream stream) { bool state = true; try { var putObjectRequest = new PutObjectRequest(bucketName, objectName, stream); putObjectRequest.StreamTransferProgress += streamProgressCallback; _ossClient.PutObject(putObjectRequest); } catch (OssException ex) { throw new AggregateException($"Failed with error code: {ex.ErrorCode}; Error info: { ex.Message}. \nRequestID: {ex.RequestId}\tHostID: {ex.HostId}"); } catch (Exception ex) { throw new AggregateException(ex.Message); } return state; } // 獲取上傳進度。 private static void streamProgressCallback(object sender, StreamTransferProgressArgs args) { System.Console.WriteLine($"ProgressCallback - Progress: {args.TransferredBytes * 100 / args.TotalBytes}%, TotalBytes:{args.TotalBytes}, TransferredBytes:{args.TransferredBytes}"); } /// <summary> /// 斷點續傳上傳方法 /// </summary> /// <param name="BucketName"></param> /// <param name="objectName"></param> /// <param name="stream"></param> /// <param name="CheckpointDir"></param> /// <returns></returns> /// <exception cref="AggregateException"></exception> public async Task<bool> BreakPoint(string BucketName, string objectName, Stream stream, string CheckpointDir) { bool back = false; try { // 通過UploadFileRequest設置多個參數。 UploadObjectRequest request = new UploadObjectRequest(BucketName, objectName, stream) { // 指定上傳的分片大小。 PartSize = 8 * 1024 * 1024, // 指定並發線程數。 ParallelThreadCount = 10, // checkpointDir保存斷點續傳的中間狀態,用於失敗后繼續上傳。 // 如果checkpointDir為null,斷點續傳功能不會生效,每次失敗后都會重新上傳。 CheckpointDir = CheckpointDir, UploadStream = stream }; // 斷點續傳上傳。 _ossClient.ResumableUploadObject(request); return true; } catch (OssException ex) { throw new AggregateException($"Failed with error code: {ex.ErrorCode}; Error info: {ex.Message}. \nRequestID:{ex.RequestId}\tHostID:{ex.HostId}"); } catch (Exception ex) { throw new AggregateException(ex.Message); } } /// <summary> /// 壓縮圖片 /// </summary> /// <param name="buffer"></param> /// <param name="targetSize">目標大小</param> /// <param name="orientation">旋轉方向</param> /// <returns></returns> private Byte[] GetThumbnail(byte[] buffer, int targetSize, int orientation = 0) { using (var memoryStream = new MemoryStream(buffer)) { if (targetSize == 0) { return buffer; } using (Image image = new Bitmap(memoryStream)) { if (image.Width < targetSize) { return buffer; } //方向旋轉 Rotation(image, image.Width, image.Height, 0); //計算比例 var data = CalculateDimensions(image.Size, targetSize); //開始壓縮 System.Drawing.Image thumbImage = image.GetThumbnailImage(data.Width, data.Height, new Image.GetThumbnailImageAbort(ThumbnailCallback), System.IntPtr.Zero); using MemoryStream backStream = new MemoryStream(); thumbImage.Save(backStream, ImageFormat.Jpeg); //關閉縮略圖對象 thumbImage.Dispose(); return backStream.GetBuffer(); } } } private bool ThumbnailCallback() { return false; } /// <summary> /// 方向選擇 旋轉 /// </summary> /// <param name="image"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="orientation"></param> private void Rotation(Image image, int width, int height, int orientation) { int ow = width; switch (orientation) { case 2: image.RotateFlip(RotateFlipType.RotateNoneFlipX); break; case 3: image.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case 4: image.RotateFlip(RotateFlipType.RotateNoneFlipY); break; case 5: image.RotateFlip(RotateFlipType.Rotate90FlipX); break; case 6: image.RotateFlip(RotateFlipType.Rotate90FlipNone); width = height; height = ow; break; case 7: image.RotateFlip(RotateFlipType.Rotate270FlipX); break; case 8: image.RotateFlip(RotateFlipType.Rotate270FlipNone); width = height; height = ow; break; default: break; } } private Size CalculateDimensions(Size oldSize, int targetSize, bool autoResize = false) { Size newSize = new Size(); if (autoResize && oldSize.Height > oldSize.Width) { newSize.Width = (int)(oldSize.Width * ((float)targetSize / (float)oldSize.Height)); newSize.Height = targetSize; } else { newSize.Width = targetSize; newSize.Height = (int)(oldSize.Height * ((float)targetSize / (float)oldSize.Width)); } return newSize; } /// <summary> /// MD5加密 /// </summary> /// <param name="stream"></param> /// <returns></returns> private string ComputeMd5Hash(MemoryStream stream) { string hash = ""; using (MD5 md5 = MD5.Create()) { stream.Position = 0; foreach (var item in md5.ComputeHash(stream)) { hash += item.ToString("x2"); } } return hash; } /// <summary> /// 獲取圖片的寬高 /// </summary> /// <param name="file"></param> /// <returns></returns> public async Task<Tuple<int, int>> GetImagesInfo(IFormFile file) { int width = 0; int height = 0; using (var memoryStream = new MemoryStream()) { await file.CopyToAsync(memoryStream); using (Bitmap pic = new Bitmap(memoryStream)) { width = pic.Size.Width; height = pic.Size.Height; } } return new Tuple<int, int>(width, height); } #endregion }
//最后在Controller 中調用
[Authorize(Policy = "UniPermission")] public class FileManageController : ControllerBase { [HttpGet] [Route("/")] [AllowAnonymous] public IActionResult Get() { return Ok("this is test"); } /// <summary> /// 上傳 10 普通上傳 20 斷點續傳上傳 30進度條上傳 /// </summary> /// <returns></returns> [HttpPost("/upload")] public async Task<IActionResult> Upload() { try { int type = 10; var files = Request.Form.Files; if (Request.Form.ContainsKey("Type")) { string str = Request?.Form["Type"].ToString(); type = int.Parse(string.IsNullOrEmpty(str) ? "10" : str); } List<FileBaseRequest> fileBaseRequests = new List<FileBaseRequest>(); foreach (var file in files) { var result = await OSSHelper._().HttpUpload(file, type); fileBaseRequests.Add(result); } return Ok(new ReturnBox { Data = fileBaseRequests }); } catch (System.Exception ex) { return Ok(new ReturnBox { Code = 400, Message = ex.Message.ToString() }); throw; } } /// <summary> /// 批量下載 /// </summary> /// <param name="downFileInfos"></param> /// <returns></returns> [HttpPost("/downloads")] public async Task<IActionResult> Download([FromBody] List<DownFileInfo> downFileInfos) { var result = await OSSHelper._().HttpDownloadList(downFileInfos); return Ok(result); } /// <summary> /// 單條下載 /// </summary> /// <param name="url"></param> /// <returns></returns> [HttpGet("/download")] [AllowAnonymous] public async Task<IActionResult> Packing(string url)//JsonElement jsonElement { var result = await OSSHelper._().HttpDownload(url); return File(result, "image/jpeg"); } }
一切准備就緒后 使用 postman 測試
成功后返回當前圖片的信息,在oss 中 生成不同類型的圖片 選中圖片能看到圖片對應的 url
在本項目上傳中使用的是簡單上傳
針對更多的上傳方式 參考官方文檔 https://www.alibabacloud.com/help/zh/doc-detail/91093.htm?spm=a2c63.p38356.b99.680.5fab7207rHS5QX
好了目前到這里就結束了 可自行擴展 僅供參考