之前在阿裡雲ECS 99元/年的活動實例上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的對象存儲開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的對象存儲應用。 ...
最新內容優先發佈於個人博客:小虎技術分享站,隨後逐步搬運到博客園。
創作不易,如果覺得有用請在Github上為博主點亮一顆小星星吧!
目的
之前在阿裡雲ECS 99元/年的活動實例上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的對象存儲開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的對象存儲應用。
完整代碼托管於Github:mrchipset/simple-wpf
包含的小知識點
- 通過AWSSDK使用S3 API
- 通過App.config對伺服器的Endpoint和AccessKey進行設置
- 使用非同步的方法響應按鈕事件
小工具的界面可以實現簡單地選擇文件上傳到桶存儲中。
實現過程
- 創建一個WPF項目,並完成如上圖的佈局
- 在項目中添加用戶配置文件 App.config來保存服務調用的地址和訪問密鑰等信息
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="endpoint" value="YOUR_S3_ENDPOINT_URL"/>
<add key="accessKey" value="YOUR_ACCESS_KEY"/>
<add key="secretKey" value="YOUR_SECRET_KEY"/>
</appSettings>
</configuration>
編寫一個方法,在程式啟動的時候導入連接參數配置
private void loadConfiguration()
{
NameValueCollection appConfig = ConfigurationManager.AppSettings;
if (string.IsNullOrEmpty(appConfig["endpoint"]))
{
ConfigurationManager.AppSettings.Set("endpoint", "endpoint");
MessageBox.Show(this, "Endpoint is not set in the App.Config", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.Close();
return;
}
if (string.IsNullOrEmpty(appConfig["accessKey"]))
{
MessageBox.Show(this, "AccessKey is not set in the App.Config", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.Close();
return;
}
if (string.IsNullOrEmpty(appConfig["secretKey"]))
{
MessageBox.Show(this, "SecretKey is not set in the App.Config", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.Close();
return;
}
_endpoint = appConfig["endpoint"];
_accessKey = appConfig["accessKey"];
_secretKey = appConfig["secretKey"];
}
- 為按鈕添加響應處理函數
由於上傳需要一定的時間來完成,因此我們用async
關鍵字修飾上傳按鈕的點擊事件處理函數,這樣即時在上傳過程中UI界面的操作也不會卡頓。函數原型如下,如果對C#的非同步操作不是很熟悉的同學可以參考這篇博文:C# 使用基本的async/await實現非同步
private async void uploadBtn_Click(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Bucket: {Bucket}");
sb.AppendLine($"File: {UploadFile}");
statusTxtBlk.Text = sb.ToString();
var ret = await UploadFileAsync();
if (ret)
{
statusTxtBlk.Text = "Upload Successfully!";
}
}
- 編寫上傳函數
現在到了本文最關鍵的一步,編寫S3 Object上傳介面。其實S3的介面都替我們封裝好了,只需要按照官方demo的流程進行調用即可。
先創建憑據對象和配置對象,然後創建客戶端對象和上傳請求,即可用客戶端對象的上傳方法進行上傳。服務函數的完整代碼如下:
private async Task<bool> UploadFileAsync()
{
var credentials = new BasicAWSCredentials(_accessKey, _secretKey);
var clientConfig = new AmazonS3Config
{
ForcePathStyle = true,
ServiceURL = _endpoint,
};
bool ret = true;
using (var client = new AmazonS3Client(credentials, clientConfig))
{
try
{
var putRequest = new PutObjectRequest
{
BucketName = _bucket,
FilePath = UploadFile
};
var response = await client.PutObjectAsync(putRequest);
}
catch(FileNotFoundException e)
{
ret = false;
this.Dispatcher.Invoke(new Action(() => this.statusTxtBlk.Text = e.Message));
}
catch (AmazonS3Exception e)
{
ret = false;
if (e.ErrorCode != null &&
(e.ErrorCode.Equals("InvalidAccessKeyId") ||
e.ErrorCode.Equals("InvalidSecurity")))
{
this.Dispatcher.Invoke(new Action(() => this.statusTxtBlk.Text = "Please check the provided AWS Credentials"));
} else
{
this.Dispatcher.Invoke(new Action(() => this.statusTxtBlk.Text = $"An error occurred with the message '{e.Message}' when writing an object"));
}
}
}
return ret;
}
註意
MINIO
在使用S3函數時必須要在AmazonS3Config
中設置ForcePathStyle
為True
。
最終實現的效果