【ASP.NET Core MVC】ファイルをAzure Blob Storageにアップロードする

C#

ASP.NET Core MVCアプリから画像ファイルをアップロードして、Azure Blob Storageにファイルを保存する方法について解説します。

※Azure Blob Storageとは

テキストファイルやバイナリデータといった非構造化データを保存できる、Azureのオブジェクトストレージサービスです。

Blob Storageには3種類のリソースがあり、以下のような関係になっています。

公式ドキュメントより引用
  • ストレージアカウント:Azureストレージサービスを使用するためのアカウント
  • コンテナ:フォルダのようなもので、ストレージアカウント直下に直接ファイルを格納できないため疑似的に作成する
  • BLOB:コンテナ内に格納されるファイル

今回はAzureポータルからストレージアカウントを作成した後、C#のコードからコンテナを作成し、その中のBLOBにアップロードした画像ファイルを保存してみます。

環境

  • Visual Studio 2022
  • .NET 6

前提

  • Azureアカウントが作成済みであること

ストレージアカウントの作成

まずストレージアカウントの作成方法について説明します。
既に作成済みの場合は飛ばしてください。

ストレージアカウントの作成

Azureポータルを開いたら、メニューから「ストレージアカウント」を選択します。
その画面内にある「作成」をクリックすると、以下のストレージアカウント作成画面が開きます。

主な設定項目は以下の通りです。費用がかからないようにするため、オプションはレベルを落としたものを選択しています。

  • リソースグループ:任意の名前で新規作成します。既存のリソースグループがある場合はそれを選択してもOKです。
  • ストレージアカウント名:任意の名前を設定します。英子文字と数字しか使えません。
  • 地域:日本国内の場合は一般的に「Japan East」か「Japan West」を選択します。
  • パフォーマンス:サンプル用なのでStandardを選択します。
  • 冗長性:サンプル用なので一番冗長性が低い「ローカル冗長ストレージ」を選択します。

その他の設定はデフォルトのもので大丈夫です。

設定できたら、「確認および作成」画面からストレージアカウントを作成しましょう。

以下のように表示されたら作成完了です。リソースに移動します。

接続文字列の確認

ストレージアカウントの左メニューにある「アクセスキー」を開くと、ストレージに必要な接続文字列を確認することができます。接続文字列は後ほど使用します。
※左上の「キーの表示」をクリックすると接続文字列がコピーできるようになります。

サンプルコード

それではASP.NET Core MVCのサンプルコードを用いて解説します。

作成するのは、画像を1つ選択してアップロードボタンをクリックするとその画像がAzure Blob Storage内に保存されるというシンプルなものです。

準備

Visual StudioでASP.NET Core MVC(.NET 6)のプロジェクトを作成したら、まず先ほど確認した接続文字列(key1)をコピーして、appsettings.jsonファイル内に記載します。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "StorageAccount": "<コピーした接続文字列>"
  }
}

次に、Blob Storageへの接続に必要なライブラリ「Azure.Storage.Blobs」をNuGet Package Managerなどからプロジェクトにインストールしておきます。

以上でストレージアカウントに接続する準備は完了です。

ビュー

@model UploadModel
@{
    ViewData["Title"] = "ファイルアップロード";
}

<h1>画像ファイルアップロード</h1>

@if (ViewData["Result"] != null)
{
    @ViewData["Result"];
}

<form asp-action="Index" enctype="multipart/form-data" method="post">
    <div asp-validation-summary="All" class="text-danger"></div>
    <div class="mb-3">
        <input asp-for=File class="form-control" type="file">
    </div>
    <div class="form-group">
        <input class="btn btn-primary" type="submit" value="アップロード" />
    </div>
</form>

まずはビューです。

ファイルを選択するためのinputフォームとアップロードボタン、コントローラー側からの結果メッセージを表示する記述などで構成されています。

ポイントは、フォーム送信時のenctypeに”multipart/form-data” を指定している点です。これを指定しないとコントローラー側でnullになってしまいます。

モデル

using System.ComponentModel.DataAnnotations;

namespace SampleApplication.Models
{
    /// <summary>
    /// アップロードファイル用モデル
    /// ※アップロードされたファイルはIFormFile型として送信される
    /// </summary>
    public class UploadModel
    {
        [UploadFile]
        public IFormFile? File { get; set; }
    }

    /// <summary>
    /// アップロードファイル検証用のカスタム属性
    /// </summary>
    public class UploadFileAttribute : ValidationAttribute
    {
        // 許可するファイルサイズ上限(今回は2MBを指定)
        private readonly long fileSizeLimit = 2097152;

        // 許可する拡張子
        private readonly string[] permittedExtensions = { ".jpg", ".jpeg", ".png", ".gif" };

        // 検証メソッド
        protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
        {
           var upload = (UploadModel)validationContext.ObjectInstance;

            // ファイルが存在しない場合はエラー
            if (upload.File == null)
            {
                return new ValidationResult("ファイルを選択してください。");
            }

            // ファイルサイズ上限より大きい場合はエラー
            if (upload.File.Length > fileSizeLimit)
            {
                return new ValidationResult("ファイルサイズが大きすぎます。");
            }

            // 小文字に変換したファイルの拡張子を取得
            var extension = Path.GetExtension(upload.File.FileName).ToLowerInvariant();

            // 画像の拡張子でない場合はエラー
            if (string.IsNullOrEmpty(extension) || !permittedExtensions.Contains(extension))
            {
                return new ValidationResult("画像ファイルを選択してください。");
            }

            return ValidationResult.Success;
        }
    }
}

アップロードファイル用のモデルと、アップロードされたファイルを検証するためにカスタム検証属性「UploadFile」を用意しました。

なんでもアップロードされてしまうのはセキュリティ上よろしくないため、下記ドキュメントを参考にファイルサイズや拡張子の検証を行っています。

ASP.NET Core でファイルをアップロードする
モデル バインドとストリーミングを使用して、ASP.NET Core MVC でファイルをアップロードする方法。

コントローラー

using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;
using SampleApplication.Models;

namespace SampleApplication.Controllers
{
    [AutoValidateAntiforgeryToken]
    public class HomeController : Controller
    {
        IConfiguration Configuration { get; }

        // 設定ファイルから接続文字列を取得するためIConfigurationを注入
        public HomeController(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 画像ファイルがアップロードされた場合はBlob Storageに保存する
        /// </summary>
        /// <param name="upload">フォームからアップロードされたファイル</param>
        [HttpPost]
        public async Task<IActionResult> Index([FromForm] UploadModel upload)
        {
            if (!ModelState.IsValid)
            {
                return View(upload);
            }

            // 設定ファイルからストレージアカウントの接続文字列を取得
            var connectionString = Configuration.GetConnectionString("AzureStorage");

            // Blob Storageのコンテナ名(確実に一意にするためにGUIDを連結)
            var containerName = $"sample{Guid.NewGuid()}";

            try
            {
                // BlobServiceClientクラスのインスタンスを作成
                var blobServiceClient = new BlobServiceClient(connectionString);

                // コンテナを作成する
                BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);

                // BlobClientクラスのインスタンスを取得
                var blobClient = containerClient.GetBlobClient(upload.File.FileName);

                // ファイルをBLOBにアップロードする
                await blobClient.UploadAsync(upload.File.OpenReadStream());

                ViewData["Result"] = "ファイルをアップロードしました!";
            }
            catch
            {
                ViewData["Result"] = "ファイルのアップロードに失敗しました。";
            }

            return View();
        }
    }
}

Blob Storageへの接続からファイルのアップロードまでの流れを簡単に説明します。

  1. 接続文字列からBLOBコンテナを操作するためのBlobServiceClientクラスのインスタンスを生成する
  2. BlobServiceClientのCreateBlobContainerAsyncメソッドでコンテナを作成する
    ※同じ名前のコンテナが既に存在する場合は例外がスローされる
  3. 戻り値のBlobContainerClientクラスのGetBlobClientメソッドで、BlobClientクラスのインスタンスを生成する
  4. BlobClientクラスのUploadAsyncメソッドで、ファイルをアップロードする
    ※同じ名前のファイルが既に存在する場合は例外がスローされる
    ※第2引数のoverwriteをtrueに指定すると、既に存在する場合はファイルが上書きされる

サンプルコードの実行

適当な画像を選択してアップロードボタンをクリックします。

「ファイルをアップロードしました!」と表示されれば処理成功です。

Azureポータルにログインしてストレージアカウントを見てみると、アップロードしたファイルが格納されていることが確認できます。

以上、画像ファイルをアップロードしてAzure Blob Storageに保存するまでを確認しました。

他にBLOBのダウンロードや一覧の取得も可能なので、興味のある方はぜひ試してみてください。

参考ドキュメント

․NET CoreからAzure Blob Storageにファイルをアップロードする方法について

クイック スタート: Azure Blob Storage ライブラリ - .NET
このクイックスタートでは、.NET 用 Azure Blob Storage クライアント ライブラリを使用して、BLOB (オブジェクト) ストレージ内にコンテナーと BLOB を作成する方法について説明します。 次に、ローカル コンピューターに BLOB をダウンロードする方法と、コンテナー内のすべての BLOB ...

カスタム検証属性について

ASP.NET Core MVC でのモデルの検証
ASP.NET Core MVC および Razor Pages でのモデルの検証について説明します。

おすすめ書籍

著:日本マイクロソフト株式会社
¥2,090 (2023/09/29 20:25時点 | Amazon調べ)
日経BP
¥3,740 (2023/09/28 22:57時点 | Amazon調べ)

コメント

タイトルとURLをコピーしました