【Razor Pages】BlobストレージからファイルをZip化してダウンロードする

Razor PagesでBlobストレージに格納したファイルを取得し、ZIPファイルとしてダウンロードさせるボタンを実装します。

## 実装する機能

- クリック時にpostリクエストを実行するボタン
- Blobストレージからファイルを取得
- ファイルをZIP化してダウンロード

## 環境
- .NET Core 3.1.9
- Azure.Storage.Blobs 12.7.0
- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 3.1.9

## postリクエストを実行するボタン
asp-page-handlerでハンドラメソッドを指定します。

```html:Index.cshtml
<form method="post">
    <input asp-page-handler="Download" value="ダウンロード" type="submit" />
</form>
```
OnPostDownloadで上記リクエストを受け取れます。
今回はDonwloadメソッドを実行するように実装します。

```C#:Index.cshtml.cs
public async Task<IActionResult> OnPostDownload()
{
     return await Download();
}       
```

## Blobストレージからファイルを取得
今回はSAS URIでアクセスします。
ファイルを格納しているコンテナーのSAS URIを取得します。

- SAS URI: `http://xxxxx/xxxx`

```C#:Index.cshtml.cs　Download()
// SAS URI
string sasUri = "http://xxxxx/xxxx";
// ダウンロード対象のファイル名
string targetFileName = "testFile.txt";

BlobContainerClient containerClient = new BlobContainerClient(new Uri(sasUri), null);
BlobClient blobClient = containerClient.GetBlobClient(targetFileName);
BlobDownloadInfo downloadInfo = await blob.DownloadAsync();
```

## ファイルをZIP化してダウンロード
メモリストリームでZIP化処理を実行します。

```C#:Index.cshtml.cs　Download()
byte[] compressedBytes;

using (var memoryStream = new MemoryStream())
{
    using (var zipArchive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        var entry = zipArchive.CreateEntry(targetFileName);
        using (var es = entry.Open())
        {
            //Blobストレージから取得したファイルをコピー
            await downloadInfo.Content.CopyToAsync(es);
        }
    }
    compressedBytes = memoryStream.ToArray();
}
```
Zip化したファイルをレスポンスとして返します。

```C#:Index.cshtml.cs　Download()
string zipName ="test.zip";
return File(compressedBytes, "application/zip", zipName);
```
## まとめ
完成したソースコードです。

#### フォームのダウンロードボタン

```html:Index.cshtml
<form method="post">
    <input asp-page-handler="Download" value="ダウンロード" type="submit" />
</form>
```
#### POSTのハンドラメソッド

```C#:Index.cshtml.cs　OnPostDownload()
public async Task<IActionResult> OnPostDownload()
{
     return await Download();
}       
```
#### Downloadメソッド

2つのファイルを取得し、ZIP化するようにしました。

```C#:Index.cshtml.cs　Download()
public async Task<IActionResult> Download()
{
    // SAS URI
    string sasUri = "http://xxxxx/xxxx";
    // ダウンロード対象のファイル名
    string[] targetFileNameList = {"testFile1.txt", "testFile2.txt"};
    
    BlobContainerClient containerClient = new BlobContainerClient(new Uri(sasUri), null);

    byte[] compressedBytes;

    using (var memoryStream = new MemoryStream())
    {
        using (var zipArchive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
        {
            foreach (var targetFileName in targetFileNameList)
            {
                BlobClient blobClient = containerClient.GetBlobClient(targetFileName);
                var entry = zipArchive.CreateEntry(targetFileName);
                using (var es = entry.Open())
                {
                    //Blobストレージから取得したファイルをコピー
                    await downloadInfo.Content.CopyToAsync(es);
                }
            }
        }
        compressedBytes = memoryStream.ToArray();
    }

    string zipName ="test.zip";
    return File(compressedBytes, "application/zip", zipName);
}
```

## 参考記事
- https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/search?view=aspnetcore-3.1
- https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-quickstart-blobs-dotnet
- https://kiyokura.hateblo.jp/entry/2015/03/25/233117