# ลองเขียนโค้ดอัพโหลดไฟล์กันบ้าง

หลังจากที่เราได้ลองสร้าง Azure Storage และทำการอัพโหลดไฟล์ผ่านหน้าเว็บไปแล้ว ในรอบนี้เราจะลองเขียนโค้ด เพื่อทำการจัดการของต่างๆใน Azure Storage กันดูบ้างนะ ส่วนใครที่ยังไม่ได้อ่านการอัพโหลดผ่านเว็บลองไปอ่านได้จากลิงค์ด้านล่างนี้

{% content-ref url="create" %}
[create](https://www.saladpuk.com/cloud/azure-storage/blobs/create)
{% endcontent-ref %}

## 🤔 เขียนโค้ดติดต่อ Azure Storage ยังไง ?

ในรอบนี้ผมจะใช้ภาษา C# .NET Core เขียนโค้ดนะครับ ส่วนภาษาอื่นๆไม่ต้องน้อยใจ ด้านล่างสุดผมทำลิงค์ของพวกภาษา Java, Node.js, Python, JavaScript, Go, PHP, Ruby ไว้เรียบร้อยแล้วลองดูได้

### สร้างโปรเจค

ในรอบนี้ผมจะใช้ .NET Core ในการสร้างโปรเจคนะครับ ดังนั้นเริ่มต้นก็เปิด command prompt หรือ terminal ขึ้นมาเลยแล้วใช้คำสั่งสร้างโปรเจคกันเลย ส่วนใครที่ยังไม่ได้ลง .NET Core ก็สามารไปลงได้จากลิงค์นี้ครับ [Download .NET Core ](https://dotnet.microsoft.com/download)

```
dotnet new console -n blob-quickstart
```

> blob-quickstart คือชื่อโปรเจคนะครับ อยากได้ชื่ออื่นก็เปลี่ยนได้เลย

ตอนนี้เราก็จะได้โปรเจคมา 1 ตัวละ ถัดไปก็เข้าไปที่โปรเจคนั้นครับด้วยคำสั่งด้านล่างนี้ (ใครที่เปลี่ยนชื่อโปรเจคก็ใส่ชื่อเป็นชื่อโปรเจคที่ตัวเองตั้งไว้นะ)

```
cd blob-quickstart
```

ทดสอบว่าโปรเจคไม่มีปัญหาอะไรด้วยคำสั่งด้านล่าง

```
dotnet build
```

ซึ่งถ้าไม่มีปัญหาอะไรก็น่าจะได้ผลลัพท์ออกมาแบบนี้

```
Build succeeded.
    0 Warning(s)
    0 Error(s)
```

### ติดตั้ง Library เพื่อทำงานกับ Azure Storage

ตัวโปรเจคที่เราสร้างขึ้นมามันจะไม่สามารถทำงานกับ Azure Storage ได้ ดังนั้นเราเลยต้องลง library เสริมโดยใช้คำสั่งด้านล่างก็เป็นอันเสร็จสิ้นพิธี

```
dotnet add package Microsoft.Azure.Storage.Blob
```

### เขียนโค้ดติดต่อ Azure Storage

คราวนี้ให้เราเปิด Visual Studio Code ขึ้นมา โดยใช้คำสั่ง `code .` ภายใน command prompt/terminal ได้เลย หรือจะเปิด Visual Studio Code แล้วเปิด folder มาที่ตัวโปรเจคก็ได้ แล้วก็เปิดไฟล์ `Program.cs` ขึ้นมารอเลย

(ใครที่ยังไม่มี Visual Studio Code สามารถดาวโหลดได้จากลิงค์นี้นะ [Download Visual Studio Code](https://code.visualstudio.com/))

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LpMnsnPF6DKs8Jwaexo%2Fimage.png?generation=1583529125044975\&alt=media)

{% hint style="info" %}
**Visual Studio Code: C# Extension**\
ในตัวอย่างที่เป็นสีสวยงาม เพราะผมลง extension 2 ตัวให้กับ Visual Studio Code นะครับ ถ้าสนใจก็กดติดตั้งได้จากลิงค์ด้านล่างเลย

* [C#](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
* [C# Extensions](https://marketplace.visualstudio.com/items?itemName=jchannon.csharpextensions)
  {% endhint %}

ถัดมาผมก็จะเขียนโค้ดให้มันเตรียมทำงานกับ Azure Storage ไว้ประมาณนี้นะครับ

```csharp
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;

namespace blob_quickstart
{
    class Program
    {
        public static void Main()
        {
            Console.WriteLine("Processing.");

            ProcessAsync().GetAwaiter().GetResult();

            Console.WriteLine("All done.");
            Console.ReadLine();
        }

        private static async Task ProcessAsync()
        {
        }
    }
}
```

ตัวโค้ดจะเรียกใช้งาน method `ProcessAsync()` ซึ่งผมตั้งใจว่าจะให้มันเป็นตัวติดต่อไปทำงานกับ Blob storage ดังนั้นเราก็แก้เจ้า method นี้ตามด้านล่างเลย

```csharp
private static async Task ProcessAsync()
{
    var connectionString = "YOUR_CONNECTION_STRING_HERE";

    CloudStorageAccount storageAccount;
    if (CloudStorageAccount.TryParse(connectionString, out storageAccount))
    {
        // พร้อมทำงานกับ Blob Storage แล้ว
    }
    else
    {
        Console.WriteLine("The connection string isn't valid");
        Console.WriteLine("Press any key to exit the application.");
    }
}
```

ในโค้ดด้านบนเราจะทำการเชื่อมต่อไปยัง Blob Storage ซึ่งการเชื่อมต่อนั้นมันจะต้องการ Key บางอย่างเพื่อยืนยันว่าคนที่ต่อเข้ามามีสิทธิ์ที่ถูกต้องด้วย (ในโค้ดบรรทัดที่ 3) ดังนั้นในขั้นตอนถัดไปเราก็จะไปเอา Key มาครับ

#### เตรียม connection สำหรับต่อ Azure Storage

ตัวโค้ดที่เราจะเขียนนั้น มันจะต้องติดต่อไปที่ Azure Storage เพื่อทำการอัพโหลดของต่างๆเข้าไป ซึ่งการที่จะทำแบบนั้นได้เราจะต้องไปเอาสิทธิ์ในการอ่านเขียนไฟล์มาก่อน ดังนั้นเราก็จะไปเอาสิทธิ์ที่ว่านี้จาก Storage account ของเรา โดยเข้าไปที่ [Azure portal](https://portal.azure.com/) แล้วเปิด Storage account ของเราขึ้นมาแล้วเลือกไปที่เมนู **Access keys**

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LoQYL637JIu1UMSZFuW%2Fimage.png?generation=1583529132258469\&alt=media)

ภายใน Access keys เขาจะมี key ให้เรา 2 ตัว ส่วนเราจะใช้ key ตัวไหนก็ได้ ซึ่งในตัวอย่างผมจะใช้ key1 นะครับ ดังนั้นก็กด Copy Connection string มาเลย

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LoAMuM0HBo1mo8_OA6o%2Fimage.png?generation=1583529143869010\&alt=media)

คราวนี้เราก็จะเอา connection string ที่ copy มาไปวางใส่ในโค้ดของเรา ในบรรทีดที่ 3 ก็จะได้ประมาณนี้ครับ

```csharp
var connectionString = "DefaultEndpointsProtocol=https;AccountName=saladpukstorage;AccountKey=V84hggJN/t56SYwQHoMDUt5kFD2bOOtUdxwK5ndMdRCyBZ4kAo8WLz7pU/H09zfrdS+SmmC8aYJsrWwoYubm4Q==;EndpointSuffix=core.windows.net";
```

{% hint style="warning" %}
**ข้อควรระวัง**\
สำหรับงานที่เป็น production จริงๆไม่ควรทำแบบนี้นะครับ มันจะกลายเป็น hard code ซึ่งถ้าเราจะเปลี่ยน connection string เมื่อไหร่ก็ต้อง compile ใหม่ทุกครั้ง ของจริงควรเขียนเป็น configuration ที่แก้ไขได้อีกทีครับ และการไปเอา connection string ตัวจริงมาใช้ก็ไม่เหมาะครับ มันมีการเข้าถึง key ได้หลายแบบเลยเช่น **SAS** อะไรพวกนี้ ซึ่งเดี๋ยวในบทถัดๆไปจะกล่าวถึงอีกทีครับ
{% endhint %}

ตอนนี้โค้ดเราก็น่าจะสามารถเชื่อมต่อ Blob Storage ได้แล้วนะครับ

### เขียนโค้ดสร้าง Container

ถัดมาเราก็จะลองสร้าง **Container** ขึ้นมาเพื่อเอาไว้เก็บไฟล์ที่เราจะอัพโหลดขึ้นไปนะครับ ซึ่งในตัวอย่างผมจะสร้าง Container ชื่อ **saladpuk-upload-by-code** ซึ่งผมก็จะไปแก้ไขโค้ดที่อยู่ใน `if` กันนะให้เป็นแบบนี้

```csharp
var cloudBlobClient = storageAccount.CreateCloudBlobClient();
var cloudBlobContainer = cloudBlobClient.GetContainerReference("saladpuk-upload-by-code");
await cloudBlobContainer.CreateIfNotExistsAsync();
```

เจ้าตัว Container ที่ผมสร้างขึ้นมาใหม่นี้ โดยปรกติมันจะโดนกำหนดสิทธิ์ในการเข้าถึงเป็น **private** หรือพูดง่ายๆคือไม่เปิดให้คนอื่นดูเลยนอกจากคนที่มีสิทธิ์ แต่ในตัวอย่างนี้ผมจะเปิดสิทธิ์ให้คนอื่นเข้าถึงได้ เพราะจะทำเป็นคล้ายๆเว็บฝากรูป ดังนั้นผมก็จะเขียนโค้ดต่อใน `if` อีกนิดหน่อยเพื่อกำหนดสิทธิ์การเข้าถึงมันใหม่ตามนี้

```csharp
var permissions = new BlobContainerPermissions
{
    PublicAccess = BlobContainerPublicAccessType.Blob
};
await cloudBlobContainer.SetPermissionsAsync(permissions);
```

เพียงเท่านี้เราก็จะได้ Container ใหม่แล้วนะครับ

### เขียนโค้ดอัพโหลดไฟล์

ถัดมาผมก็จะเขียนโค้ดอัพโหลดรูปในเครื่องขึ้นไปที่ Blob Storage นะครับ ซึ่งรูปของผมอยู่ที่ `d:\saladpakLogo-05.png` และผมจะตั้งชื่อที่อัพโหลดขึ้นไปให้ชื่อว่า `img01.png` ด้วยดังนั้นผมเขียนโค้ดภายใน `if` ออกมาเป็นแบบนี้

```csharp
var file = new FileStream(@"d:\saladpakLogo-05.png", FileMode.Open);
var cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference("img01.png");
cloudBlockBlob.Properties.ContentType = "image/png";
await cloudBlockBlob.UploadFromStreamAsync(file);
```

เป็นอันเรียบร้อยแล้ว ดังนั้นผมก็จะลองสั่งให้มันทำงานดู โดยการเข้าไปที่ command prompt/terminal โดยการใช้คำสั่งนี้

```
dotnet run
```

ในหน้าจอ command prompt/terminal ก็น่าจะได้ผลลัพท์แบบนี้ (ถ้าไม่ได้ลองไปตรวจดูนะว่าทำขั้นตอนไหนผิด)

```
Processing.
All done.
```

### ลองตรวจไฟล์ที่อัพไปดู

ไฟล์ที่เราอัพโหลดเข้าไปจะอยู่บนคลาว์ดังนั้นเราก็ต้องเข้าไปดูที่ตัว Blob Storage ของเราครับ

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M1lg0TegZbe11nkRErA%2Fimage%20\(956\).png?generation=1583529180905252\&alt=media)

เราก็จะเจอ Container ใหม่ที่เราสร้างขึ้นมาจากโค้ด ให้ลองกดมันเข้าไปเลย

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LrKTUdJbjDiCjMMGB8Q%2Fimage.png?generation=1583529125598061\&alt=media)

แล้วเราก็จะเจอรูปของเรา ก็ให้กดมันเข้าไปอีกที

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LtpIqV2V7s9p8xn2Tl1%2Fimage.png?generation=1583529181530688\&alt=media)

ถัดมาเราก็กด copy ลิงค์แล้วลองเอาไปเปิดดูใน web browser ดูครับ

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LoFxt851LdSxF0QF1nG%2Fimage.png?generation=1583529142603735\&alt=media)

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LqvyKMJhTIbnJEB5FKn%2Fimage.png?generation=1583529120177164\&alt=media)

เรียบร้อยแล้วครับ เราสามารถอัพโหลดรูปขึ้นไปบน Azure Storage ได้แล้ว และเรียกดูเหมือนเว็บฝากไฟล์ได้แบ้ว

## 📜 Source code

```csharp
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;

namespace blob_quickstart
{
    class Program
    {
        public static void Main()
        {
            Console.WriteLine("Processing.");

            ProcessAsync().GetAwaiter().GetResult();

            Console.WriteLine("All done.");
            Console.ReadLine();
        }

        private static async Task ProcessAsync()
        {
            var connectionString = "DefaultEndpointsProtocol=https;AccountName=saladpukstorage;AccountKey=V84hggJN/t56SYwQHoMDUt5kFD2bOOtUdxwK5ndMdRCyBZ4kAo8WLz7pU/H09zfrdS+SmmC8aYJsrWwoYubm4Q==;EndpointSuffix=core.windows.net";

            CloudStorageAccount storageAccount;
            if (CloudStorageAccount.TryParse(connectionString, out storageAccount))
            {
                var cloudBlobClient = storageAccount.CreateCloudBlobClient();
                var cloudBlobContainer = cloudBlobClient.GetContainerReference("saladpuk-upload-by-code");
                await cloudBlobContainer.CreateIfNotExistsAsync();

                var permissions = new BlobContainerPermissions
                {
                    PublicAccess = BlobContainerPublicAccessType.Blob
                };
                await cloudBlobContainer.SetPermissionsAsync(permissions);

                var file = new FileStream(@"d:\saladpakLogo-05.png", FileMode.Open);
                var cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference("img01.png");
                cloudBlockBlob.Properties.ContentType = "image/png";
                await cloudBlockBlob.UploadFromStreamAsync(file);
            }
            else
            {
                Console.WriteLine("The connection string isn't valid");
                Console.WriteLine("Press any key to exit the application.");
            }
        }
    }
}
```

## 🔗 ตัวอย่างภาษาอื่นๆ

* [Node.js](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-nodejs-v10)
* [Python](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-python)
* [JavaScript - Azure SDK version 10](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-javascript-client-libraries-v10)
* [JavaScript - Azure SDK version 2](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-javascript-client-libraries)
* [Go](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-go?tabs=windows)
* [PHP](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-php?tabs=windows)
* [Ruby](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-ruby)

## 🔥 ทิ้งท้ายของน่าสนใจ!!

พอเขียนบทความนี้เสร็จปุ๊ป ทาง Microsoft ก็ส่งอีเมล์แจ้งเตือนมาทันทีเลยว่า ตรวจพบ security รั่วเนื่องจากผมเอา secret ของตัว Azure Storage ไปเปิดเผยต่อสาธารณะในบทความนี้ไงล่ะ (ผมลิงค์บทความเข้ากับ GitHub) นี่คือข้อดีอีกเรื่องของการที่เราใช้คลาว์ของ Microsoft ครับ ทำให้เราอุ่นใจขึ้นเยอะเลยว่าของหลายๆอย่างเราสามารถป้องกันก่อนที่มันจะร้ายแรงจนแก้ไม่ได้ครับ

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M-VEHr1EQpC63dHa9h7%2Fimage.png?generation=1583529160567141\&alt=media)

ซึ่งเขาก็บอกรายละเอียดไว้ครบถ้วนเลย พร้อมวิธีแก้ปัญหา ดังนั้นผมก็เลยต้องไป reset key ทั้ง 2 ออกครับ (แต่จริงๆผมไม่ต้องทำก็ได้ เพราะ Storage ตัวนี้เดี๋ยวก็ลบทิ้งละเพราะเขียนบทความเสร็จแล้ว)

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-Lwi8sy6JNb4Zt2Qxb4I%2Fimage.png?generation=1583529169056811\&alt=media)
