Simple WPF: WPF實現一個MINIO等S3相容物件儲存上傳檔案的小工具

mrchip發表於2024-07-10

最新內容優先釋出於個人部落格:小虎技術分享站,隨後逐步搬運到部落格園。
創作不易,如果覺得有用請在Github上為博主點亮一顆小星星吧!

目的

之前在阿里雲ECS 99元/年的活動例項上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的物件儲存開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的物件儲存應用。

完整程式碼託管於Github:mrchipset/simple-wpf

包含的小知識點

  1. 透過AWSSDK使用S3 API
  2. 透過App.config對伺服器的Endpoint和AccessKey進行設定
  3. 使用非同步的方法響應按鈕事件

cmrQLEN2KEddprIRAYxMvUX7FZCQQvCs6B8WpQ2RHNc.png

小工具的介面可以實現簡單地選擇檔案上傳到桶儲存中。

實現過程

  1. 建立一個WPF專案,並完成如上圖的佈局
  2. 在專案中新增使用者配置檔案 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"];
}
  1. 為按鈕新增響應處理函式
    由於上傳需要一定的時間來完成,因此我們用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!";
    }
}
  1. 編寫上傳函式
    現在到了本文最關鍵的一步,編寫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 中設定ForcePathStyleTrue

最終實現的效果

lO2tSD8ec3B25NI95FWqDaeHcBm33fDjvvyklqXAbL0.gif

相關文章