【ASP.NET Core】C# 画像ファイルをBLOBでDBに登録する方法

画像ファイルをDBに保存する方法として、varbinary(MAX)のカラムにバイナリデータを登録するやり方があります。本記事ではASP.NET Core + Dapper で登録する方法を紹介します。

【検証環境】Visual Studio 2019 / ASP.NET Core 3.1 / SQL Server 2019

DBに画像を保存する方法

DBに画像を保存する方法は大きく分けて2通りあります。

ファイルパスを保存

画像はDBの外に保存し、ファイルパスをデータベースに格納するやり方です。
ファイルパスを保存するだけなので、DBの容量を節約できます。

BLOB(バイナリデータ)を保存

varbinary(MAX)のカラムにバイナリデータを格納するやり方です。
レコードの容量が大きくなってしまいますが、メリットも多くあります。

それぞれの詳しいメリット・デメリットはこちらのサイトを参照してください。

サンプルコード

先にテーブルを準備します。
テーブル「Images」に カラムvarbinary(MAX)・NULL許容「Image」を作成します。

PostController と PostIndex.cshtml を作成します。
Dapperの使い方はこちらを参照して下さい。

<form method="post" enctype="multipart/form-data" asp-controller="Post" asp-action="Index">
    <div class="form-file">
        @*画像アップロード用*@
        <input type="file" class="form-file-input" id="image" name="formFile" />
    </div>
    <div>
        @*登録ボタン*@
        <input type="submit" value="登録" name="btnname"> 
    </div>
    <div>
        @*画像取得ボタン*@
        <input type="submit" value="画像取得" name="btnname">
        @*画像表示用*@
        <img id="getimage" style="width: 100px;" src="data: image;base64, 
             @System.Convert.ToBase64String(ViewBag.image ?? new byte[] { })" />
    </div>
    <div>
        @*メッセージ*@
        @ViewBag.message
    </div>
</form>

IFormFile で画像を受け取って、MemoryStreamにコピーして、ToArrayでbyte配列に変換すれば登録できる形式になります。

using Dapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Data.SqlClient;
using System.IO;

public class PostController : Controller
{
    public ActionResult Index()
    {
        return View();
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index(IFormFile formFile, string btnname)
    {
        try
        {
            ViewBag.message = "";

            if (btnname == "登録")
            {
                InsertImage(formFile, btnname);
                ViewBag.message = "登録完了";
            }
            else if(btnname == "画像取得")
            {
                GetImage();
            }
            return View();
        }
        catch(Exception ex)
        {
            ViewBag.message = ex.Message;
            return View();
        }
    }

    private void InsertImage(IFormFile formFile, string value)
    {
        var connectionString = "環境に合わせてください。";
        using (var connection = new SqlConnection(connectionString))
        {
            //接続
            connection.Open();
            using (var tx = connection.BeginTransaction())
            {
                try
                {
                    //レコード削除
                    var sqlDelete = "DELETE FROM Images";

					//トランザクションを使う場合、第2引数にオブジェクトを渡さないとエラーになる(空でもOK)
                    connection.Execute(sqlDelete, new { } ,tx);

                    //データ挿入
                    var sqlInsert = "INSERT INTO Images (Image) VALUES (@Image)";
                    var ms = new MemoryStream();
                    formFile.CopyTo(ms);
                    var param = new { Image = ms.ToArray() };
                    connection.Execute(sqlInsert, param, tx);

                    //コミット
                    tx.Commit();
                }
                catch (Exception)
                {
                    //ロールバック
                    tx.Rollback();
                    throw;
                }
            }
        }
    }
    private void GetImage()
    {
        var connectionString = "環境に合わせてください。";
        using (var connection = new SqlConnection(connectionString))
        {
            //接続
            connection.Open();
            try
            {
                //レコード1件取得
                var sql = "SELECT TOP(1) Image FROM Images";
                var image = connection.QueryFirst<byte[]>(sql);
                ViewBag.image = image;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

アプリを起動して、URLに「/Post」を入力して遷移させます。
すると最初にこのような画面が表示されます。

画像ファイルを選択して、登録ボタンを押下すると、「登録完了」のメッセージが表示されます。

画像取得ボタンを押下すると、登録された画像が表示されることが確認できます。

DBからもバイナリデータが格納されていることが確認できます。

Leave a Reply

Your email address will not be published. Required fields are marked *