ASP.NET Core Web API で、ブラウザから fetch や axios を使って multipart/form-data 形式でアップロードされてきた Blob データをどのように取得できるかということを書きます。
axios のドキュメント Multipart Bodies のサンプルコード(抜粋下記)を見て、そこに書いてある Blob データを Web API でどのように取得できるかを考えたのがきっかけです。
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Blob([1,2,3]));
form.append('my_file', fileInput.files[0]);
上のコードの FormData を、ブラウザから JavaScript の fetch や axios を使って multipart/form-data 形式で送信すると、ボディ部分は下のようになります (Fiddler によるキャプチャ画像)。2 つ目の name が my_buffer となっているパートが Blob データです。

上のように送信されてきた my_buffer の Blob データは、ASP.NET Core Web API のアクションメソッドの引数の型を IFormFile 型とすれば取得できました。
具体的には、Web API プロジェクトで以下のクラスを定義し、
public class Blob
{
public string? My_field { get; set; }
public IFormFile? My_buffer { get; set; }
public IFormFile? My_file { get; set; }
}
それをアクションメソッドの引数に設定して、JavaScript の fetch や axios を使って FormData をアクションメソッドに POST 送信すれば、下の画像の通り My_buffer プロパティに Blob を取得できます。

MDN のドキュメント Blob に、
"File インターフェイスは Blob をベースにしており、 Blob の機能を継承してユーザーのシステム上のファイルをサポートするように拡張しています"
・・・と書いてあるとおり、input type="file" を使ってのファイルと同様の扱いになるということのようです。
最初、バイト配列として取得できるのではと思って、上の Blob クラスの My_buffer プロパティの型を byte[]? として試してみたのですが、バインドできないようで null になってしまいます。
![My_buffer プロパティが byte[]? 型の場合 My_buffer プロパティが byte[]? 型の場合](/BlogEngine/image.axd?picture=2025%2f2%2f0203Debugger1.jpg)
以下に検証に使ったコードを載せておきます。Visual Studio 2022 のテンプレートを使ってターゲットフレームワーク .NET 9.0 で作成した ASP.NET Core Web API アプリです。
Controller
using Microsoft.AspNetCore.Mvc;
using WebApi.Models;
namespace WebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UploadController : ControllerBase
{
[HttpPost("blob")]
public async Task<IActionResult> ReceiveBlob([FromForm] Blob model)
{
string result = $"My_field: {model.My_field}";
if (model.My_file != null && model.My_file.Length > 0)
{
string filename = Path.GetFileName(model.My_file.FileName);
result += $", My_file: {filename}";
}
if (model.My_buffer != null && model.My_buffer.Length > 0)
{
string array = string.Empty;
using (var stream = new MemoryStream())
{
await model.My_buffer.CopyToAsync(stream);
byte[] bytes = stream.ToArray();
foreach (byte b in bytes)
{
array += $"[{b:x2}]";
}
}
result += $", My_buffer: {array}";
}
return Content(result);
}
}
}
View
@{
ViewData["Title"] = "SendBlob";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewData["Title"] - WebApi</title>
<script type="text/javascript">
const url = "/api/upload/blob";
const upload = async () => {
const fileInput = document.getElementById("fileupload");
const resultDiv = document.getElementById("result");
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Blob([1, 2, 3]));
form.append('my_file', fileInput.files[0]);
const param = {
method: "POST",
body: form
}
const response = await fetch(url, param);
if (response.ok) {
const message = await response.text();
resultDiv.innerText = message;
} else {
resultDiv.innerText = "アップロード失敗";
}
};
window.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById("button1");
btn.addEventListener("click", upload);
});
</script>
</head>
<body>
<input type="file" name="fileupload" id="fileupload" multiple="multiple" />
<br />
<button type="button" id="button1">Upload</button>
<br />
<div id="result"></div>
</body>
</html>
上の View のコードの実行結果は以下のようになります。

(メモ: プロジェクトは VS2022 AspNet9 WebApi)