記事内に広告が含まれています

【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 8

前提

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

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

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

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

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

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

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

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

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

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

接続文字列の確認

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

サンプルコード

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

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

準備

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

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

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

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

ビュー

まずはビューです。index.cshtmlに以下のコードを記述します。

@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になってしまいます。

モデル

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

using System.ComponentModel.DataAnnotations;

namespace BlobStorageSample.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)
        {
            // UploadModel型に変換
            var upload = validationContext.ObjectInstance as UploadModel;

            // ファイルが存在しない場合はエラー
            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;
        }
    }
}

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

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

コントローラー

最後に、HomeControllerにアップロードされたファイルをBlob Storageに保存する処理を記述します。

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

namespace BlobStorageSample.Controllers
{
    [AutoValidateAntiforgeryToken]
    public class HomeController : Controller
    {
        private readonly string _connectionString = string.Empty;

        // 設定ファイルからストレージアカウントの接続文字列を取得
        public HomeController(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("StorageAccount") 
                ?? throw new ArgumentNullException("接続文字列が指定されていません。");
        }

        /// <summary>
        /// 画面表示
        /// </summary>
        public IActionResult Index() => View();

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

            // 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. BlobServiceClientCreateBlobContainerAsyncメソッドでコンテナを作成する
    ※同じ名前のコンテナが既に存在する場合は例外がスローされる
  3. 戻り値のBlobContainerClientクラスのGetBlobClientメソッドで、BlobClientクラスのインスタンスを生成する
  4. BlobClientクラスのUploadAsyncメソッドで、ファイルをアップロードする
    ※同じ名前のファイルが既に存在する場合は例外がスローされる
    ※第2引数のoverwriteをtrueに指定すると、既に存在する場合はファイルが上書きされる

サンプルコードの実行

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

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

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

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

参考ドキュメント

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

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

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

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

おすすめ書籍

著:日本マイクロソフト株式会社
¥3,762 (2024/02/27 14:17時点 | Amazon調べ)

コメント

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