如何優雅地使用騰訊雲COS-.NET篇
代碼下載地址 https://github.com/whuanle/txypx20190809
前提
創建子賬號
打開 https://console.cloud.tencent.com/cam
創建子用戶,設置子賬號策略為 AdministratorAccess
,或者參考https://cloud.tencent.com/document/product/436/11714 ,添加訪問 COS 的權限 記錄子用戶的 賬號ID
。
切換子用戶登錄。
添加 appid 密鑰
打開 https://console.cloud.tencent.com/cam/capi
新建 API 密鑰,記錄下 appid,記錄 SecretId
和 SecretKey
。
記錄 Region
打開 https://cloud.tencent.com/document/product/436/6224
可以查詢可用區/地域的 region。
本教程使用 C# 開發。
一,SDK 和使用
騰訊雲官網提供了 .NET 版本的 對象存儲(COS) SDK,並提供使用教程,教程鏈接:
https://cloud.tencent.com/document/product/436/32819
Nuget 搜索 Tencent.QCloud.Cos.Sdk
安裝即可。
using 需引入
using COSXML;
using COSXML.Auth;
using COSXML.Model.Object;
using COSXML.Model.Bucket;
using COSXML.CosException;
using COSXML.Utils;
using COSXML.Model.Service;
using COSXML.Transfer;
using COSXML.Model;
根據官方的教程,很容易編寫自己的軟件:
Ctrl + C ,然后 Ctrl + V
拷貝完畢,大概是這樣的
using System;
using System.Collections.Generic;
using System.Text;
using COSXML;
using COSXML.Auth;
using COSXML.Model.Object;
using COSXML.Model.Bucket;
using COSXML.CosException;
using COSXML.Utils;
using COSXML.Model.Service;
using COSXML.Transfer;
using COSXML.Model;
namespace CosTest
{
public class CosClient
{
CosXmlServer cosXml;
private readonly string _appid;
private readonly string _region;
public CosClient(string appid, string region)
{
_appid = appid;
_region = region;
//初始化 CosXmlConfig
//string appid = "100011070645";
//string region = "ap-guangzhou";
CosXmlConfig config = new CosXmlConfig.Builder()
.SetConnectionTimeoutMs(60000)
.SetReadWriteTimeoutMs(40000)
.IsHttps(true)
.SetAppid(appid)
.SetRegion(region)
.SetDebugLog(true)
.Build();
QCloudCredentialProvider cosCredentialProvider = null;
string secretId = "AKID62jALHsVmpfHentPs9E6lBMJ2XnnsTzH"; //"雲 API 密鑰 SecretId";
string secretKey = "CC0c1DAtNdfS0IPIvISRFtIUSCUYTAgy"; //"雲 API 密鑰 SecretKey";
long durationSecond = 600; //secretKey 有效時長,單位為 秒
cosCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, durationSecond);
//初始化 CosXmlServer
cosXml = new CosXmlServer(config, cosCredentialProvider);
}
public bool CreateBucket(string buketName)
{
try
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
PutBucketRequest request = new PutBucketRequest(buketName);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
PutBucketResult result = cosXml.PutBucket(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return true;
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return false;
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return false;
}
}
public bool SelectBucket()
{
try
{
GetServiceRequest request = new GetServiceRequest();
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
GetServiceResult result = cosXml.GetService(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return true;
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return false;
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return false;
}
}
public bool Upfile(string buketName, string key, string srcPath)
{
try
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
PutObjectRequest request = new PutObjectRequest(bucket, key, srcPath);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//設置進度回調
request.SetCosProgressCallback(delegate (long completed, long total)
{
Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
});
//執行請求
PutObjectResult result = cosXml.PutObject(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return true;
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return false;
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return false;
}
}
public void UpBigFile(string buketName, string key, string srcPath)
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
TransferManager transferManager = new TransferManager(cosXml, new TransferConfig());
COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, null, key);
uploadTask.SetSrcPath(srcPath);
uploadTask.progressCallback = delegate (long completed, long total)
{
Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
};
uploadTask.successCallback = delegate (CosResult cosResult)
{
COSXML.Transfer.COSXMLUploadTask.UploadTaskResult result = cosResult as COSXML.Transfer.COSXMLUploadTask.UploadTaskResult;
Console.WriteLine(result.GetResultInfo());
};
uploadTask.failCallback = delegate (CosClientException clientEx, CosServerException serverEx)
{
if (clientEx != null)
{
Console.WriteLine("CosClientException: " + clientEx.Message);
}
if (serverEx != null)
{
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
}
};
transferManager.Upload(uploadTask);
}
public class ResponseModel
{
public int Code { get; set; }
public string Message { get; set; }
public dynamic Data { get; set; }
}
public ResponseModel SelectObjectList(string buketName)
{
try
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
GetBucketRequest request = new GetBucketRequest(bucket);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
GetBucketResult result = cosXml.GetBucket(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return new ResponseModel { Code = 200, Data = result.GetResultInfo() };
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return new ResponseModel { Code = 200, Data = clientEx.Message };
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return new ResponseModel { Code = 200, Data = serverEx.Message };
}
}
public bool DownObject(string buketName, string key, string localDir, string localFileName)
{
try
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//設置進度回調
request.SetCosProgressCallback(delegate (long completed, long total)
{
Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
});
//執行請求
GetObjectResult result = cosXml.GetObject(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return true;
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return false;
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return false;
}
}
public bool DeleteObject(string buketName)
{
try
{
string bucket = buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
string key = "exampleobject"; //對象在存儲桶中的位置,即稱對象鍵.
DeleteObjectRequest request = new DeleteObjectRequest(bucket, key);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
DeleteObjectResult result = cosXml.DeleteObject(request);
//請求成功
Console.WriteLine(result.GetResultInfo());
return true;
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine("CosClientException: " + clientEx.Message);
return false;
}
catch (COSXML.CosException.CosServerException serverEx)
{
//請求失敗
Console.WriteLine("CosServerException: " + serverEx.GetInfo());
return false;
}
}
}
}
概覽:
但是大神說,這樣不好,程序要高內聚、低耦合,依賴與抽象而不依賴於具體實現。
那怎么辦?只能修改一下。
二,優化
1,對象構建器
對象存儲的 SDK 中,有三個重要的對象:
CosXmlConfig
提供配置 SDK 接口。QCloudCredentialProvider
提供設置密鑰信息接口。CosXmlServer
提供各種 COS API 服務接口。
但是,初始化和配置對象,過於麻煩,那么我們做一個對象構建器,實現函數式編程和鏈式語法。
/// <summary>
/// 生成Cos客戶端工具類
/// </summary>
public class CosBuilder
{
private CosXmlServer cosXml;
private string _appid;
private string _region;
private CosXmlConfig cosXmlConfig;
private QCloudCredentialProvider cosCredentialProvider;
public CosBuilder()
{
}
public CosBuilder SetAccount(string appid, string region)
{
_appid = appid;
_region = region;
return this;
}
public CosBuilder SetCosXmlServer(int ConnectionTimeoutMs = 60000, int ReadWriteTimeoutMs = 40000, bool IsHttps = true, bool SetDebugLog = true)
{
cosXmlConfig = new CosXmlConfig.Builder()
.SetConnectionTimeoutMs(ConnectionTimeoutMs)
.SetReadWriteTimeoutMs(ReadWriteTimeoutMs)
.IsHttps(true)
.SetAppid(_appid)
.SetRegion(_region)
.SetDebugLog(true)
.Build();
return this;
}
public CosBuilder SetSecret(string secretId, string secretKey, long durationSecond = 600)
{
cosCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, durationSecond);
return this;
}
public CosXmlServer Builder()
{
//初始化 CosXmlServer
cosXml = new CosXmlServer(cosXmlConfig, cosCredentialProvider);
return cosXml;
}
}
2,消息響應對象
為了統一返回消息,創建一個 Response Model 的類。
/// <summary>
/// 消息響應
/// </summary>
public class ResponseModel
{
public int Code { get; set; }
public string Message { get; set; }
public dynamic Data { get; set; }
}
3,接口
實際上,訪問 COS和控制,和存儲桶內的操作,是可以分開的。
訪問 COS 可以控制對象存儲內的所有東西,但是每個存儲桶又是一個獨立的對象。
為了松耦合,我們拆分兩個客戶端,一個用來管理連接、存儲桶等,一個用來管理存儲桶內的操作。
接口如下:
public interface ICosClient
{
// 創建存儲桶
Task<ResponseModel> CreateBucket(string buketName);
// 獲取存儲桶列表
Task<ResponseModel> SelectBucket(int tokenTome = 600);
}
public interface IBucketClient
{
// 上傳文件
Task<ResponseModel> UpFile(string key, string srcPath);
// 分塊上傳大文件
Task<ResponseModel> UpBigFile(string key, string srcPath, Action<long, long> progressCallback, Action<CosResult> successCallback);
// 查詢存儲桶的文件列表
Task<ResponseModel> SelectObjectList();
// 下載文件
Task<ResponseModel> DownObject(string key, string localDir, string localFileName);
// 刪除文件
Task<ResponseModel> DeleteObject(string buketName);
}
所有接口功能都使用異步實現。
4,COS 客戶端
基架代碼:
public class CosClient : ICosClient
{
CosXmlServer _cosXml;
private readonly string _appid;
private readonly string _region;
public CosClient(CosXmlServer cosXml)
{
_cosXml = cosXml;
}
}
創建存儲桶:
public async Task<ResponseModel> CreateBucket(string buketName)
{
try
{
string bucket = buketName + "-" + _appid;
PutBucketRequest request = new PutBucketRequest(bucket);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
PutBucketResult result = await Task.FromResult(_cosXml.PutBucket(request));
return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
}
catch (COSXML.CosException.CosClientException clientEx)
{
//請求失敗
Console.WriteLine();
return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
}
catch (COSXML.CosException.CosServerException serverEx)
{
return new ResponseModel { Code = 200, Message = "CosServerException: " + serverEx.GetInfo() };
}
}
查詢存儲桶列表
public async Task<ResponseModel> SelectBucket(int tokenTome = 600)
{
try
{
GetServiceRequest request = new GetServiceRequest();
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), tokenTome);
//執行請求
GetServiceResult result = await Task.FromResult(_cosXml.GetService(request));
return new ResponseModel { Code = 200, Message = "Success", Data = result.GetResultInfo() };
}
catch (COSXML.CosException.CosClientException clientEx)
{
return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
}
catch (CosServerException serverEx)
{
return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
}
}
5,存儲桶操作客戶端
基架代碼如下:
/// <summary>
/// 存儲桶客戶端
/// </summary>
public class BucketClient : IBucketClient
{
private readonly CosXmlServer _cosXml;
private readonly string _buketName;
private readonly string _appid;
public BucketClient(CosXmlServer cosXml, string buketName, string appid)
{
_cosXml = cosXml;
_buketName = buketName;
_appid = appid;
}
}
上傳對象
public async Task<ResponseModel> UpFile(string key, string srcPath)
{
try
{
string bucket = _buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
PutObjectRequest request = new PutObjectRequest(bucket, key, srcPath);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//設置進度回調
request.SetCosProgressCallback(delegate (long completed, long total)
{
Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
});
//執行請求
PutObjectResult result = await Task.FromResult(_cosXml.PutObject(request));
return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
}
catch (CosClientException clientEx)
{
return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
}
catch (CosServerException serverEx)
{
return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
}
}
大文件分塊上傳
/// <summary>
/// 上傳大文件、分塊上傳
/// </summary>
/// <param name="key"></param>
/// <param name="srcPath"></param>
/// <param name="progressCallback">委托,可用於顯示分塊信息</param>
/// <param name="successCallback">委托,當任務成功時回調</param>
/// <returns></returns>
public async Task<ResponseModel> UpBigFile(string key, string srcPath, Action<long, long> progressCallback, Action<CosResult> successCallback)
{
ResponseModel responseModel = new ResponseModel();
string bucket = _buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
TransferManager transferManager = new TransferManager(_cosXml, new TransferConfig());
COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, null, key);
uploadTask.SetSrcPath(srcPath);
uploadTask.progressCallback = delegate (long completed, long total)
{
progressCallback(completed, total);
//Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
};
uploadTask.successCallback = delegate (CosResult cosResult)
{
COSXMLUploadTask.UploadTaskResult result = cosResult as COSXMLUploadTask.UploadTaskResult;
successCallback(cosResult);
responseModel.Code = 200;
responseModel.Message = result.GetResultInfo();
};
uploadTask.failCallback = delegate (CosClientException clientEx, CosServerException serverEx)
{
if (clientEx != null)
{
responseModel.Code = 0;
responseModel.Message = clientEx.Message;
}
if (serverEx != null)
{
responseModel.Code = 0;
responseModel.Message = "CosServerException: " + serverEx.GetInfo();
}
};
await Task.Run(() =>
{
transferManager.Upload(uploadTask);
});
return responseModel;
}
查詢對象列表
public async Task<ResponseModel> SelectObjectList()
{
try
{
string bucket = _buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
GetBucketRequest request = new GetBucketRequest(bucket);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
GetBucketResult result = await Task.FromResult(_cosXml.GetBucket(request));
return new ResponseModel { Code = 200, Data = result.GetResultInfo() };
}
catch (CosClientException clientEx)
{
return new ResponseModel { Code = 0, Data = "CosClientException: " + clientEx.Message };
}
catch (CosServerException serverEx)
{
return new ResponseModel { Code = 0, Data = "CosServerException: " + serverEx.GetInfo() };
}
}
下載對象 、刪除對象
public async Task<ResponseModel> DownObject(string key, string localDir, string localFileName)
{
try
{
string bucket = _buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//設置進度回調
request.SetCosProgressCallback(delegate (long completed, long total)
{
Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
});
//執行請求
GetObjectResult result = await Task.FromResult(_cosXml.GetObject(request));
return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
}
catch (CosClientException clientEx)
{
return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
}
catch (CosServerException serverEx)
{
return new ResponseModel { Code = 0, Message = serverEx.GetInfo() };
}
}
public async Task<ResponseModel> DeleteObject(string buketName)
{
try
{
string bucket = _buketName + "-" + _appid; //存儲桶名稱 格式:BucketName-APPID
string key = "exampleobject"; //對象在存儲桶中的位置,即稱對象鍵.
DeleteObjectRequest request = new DeleteObjectRequest(bucket, key);
//設置簽名有效時長
request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
//執行請求
DeleteObjectResult result = await Task.FromResult(_cosXml.DeleteObject(request));
return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
}
catch (CosClientException clientEx)
{
return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
}
catch (CosServerException serverEx)
{
return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
}
}
以上代碼將官方示例作了優化。
- 依賴於抽象、實現接口;
- 松耦合;
- 異步網絡流、異步文件流;
- 統一返回信息;
- 增加匿名委托作方法參數;
- 增加靈活性。
三,使用封裝好的代碼
1,初始化
官網示例文檔:
使用修改后的代碼,你可以這樣初始化:
var cosClient = new CosBuilder()
.SetAccount("1252707544", " ap-guangzhou")
.SetCosXmlServer()
.SetSecret("AKIDEZohU6AmkeNTVPmedw65Ws462rVxLIpG", "Sn1iFi182jMARcheQ1gYIsGSROE5rSwG")
.Builder();
簡單測試代碼
static async Task Main(string[] args)
{
// 構建一個 CoxXmlServer 對象
var cosClient = new CosBuilder()
.SetAccount("125x707xx4", "ap-guangzhou")
.SetCosXmlServer()
.SetSecret("AKIxxxxxxedw65Ws462rVxLIpG", "Sn1iFi1xxxxxwG")
.Builder();
// 創建Cos連接客戶端
ICosClient client = new CosClient(cosClient, "125xx0xx44");
// 創建一個存儲桶
var result = await client.CreateBucket("fsdgerer");
Console.WriteLine("處理結果:" + result.Message);
// 查詢存儲桶列表
var c = await client.SelectBucket();
Console.WriteLine(c.Message + c.Data);
Console.ReadKey();
}
運行結果(部分重要信息使用xx屏蔽):
處理結果:200 OK
Connection: keep-alive
Date: Fri, 09 Aug 2019 14:15:00 GMT
Server: tencent-cos
x-cos-request-id: xxxxxxxx=
Content-Length: 0
Success200 OK
Connection: keep-alive
Date: Fri, 09 Aug 2019 14:15:01 GMT
Server: tencent-cos
x-cos-request-id: xxxxxxx=
Content-Type: application/xml
Content-Length: 479
{ListAllMyBuckets:
{Owner:
ID:qcs::cam::uin/1586xx146:uin/158xxx2146
DisPlayName:158x2146
}
Buckets:
{Bucket:
Name:fsdgerer-125xxx7544
Location:ap-guangzhou
CreateDate:
}
{Bucket:
Name:work-1252xxx7544
Location:ap-guangzhou
CreateDate:
}
}
}
其它不再贅述