by WebSurfer
22. October 2024 18:00
Visual Studio 2022 のテンプレートを使ってターゲットフレームワーク .NET 8.0 で ASP.NET Core Web API のプロジェクトを作成し、Visual Studio から実行すると下の画像のようにブラウザ上に swagger/index.html というページが表示され、そこから Web API のアクションメソッドを要求して応答を調べることができます。(追記: 2024/11/25 時点で、ターゲットフレームワーク .NET 9.0 で作成した Web API プロジェクトには Swagger は含まれません)
Swagger を使って (1) ファイルをアップロードする方法、及び (2) ベアラトークンを要求ヘッダに含めて送信する方法を調べましたので、備忘録として残しておくことにしました。
(1) と (2) を一つの記事に書くと長くなりすぎるので、この記事では (1) を書いて、(2) は別の記事に「その2」として書くことにします。
(1) ファイルアップロード
アクションメソッドの引数に IFormFile 型の変数を含めれば、Swagger が自動的にそれを検出してアップロードするファイルの選択が可能になり、Swagger から Web API にファイルをアップロードできるようになります。
Swagger にファイル選択のための画面を表示するには、まず、[Try it out]ボタンをクリックします。
[Try it out]ボタンをクリックすると、下のように、ブラウザが html の <input type="file" > を表示した時と同様なファイル選択を行うための画面が表示されます。
その画面でアップロードするファイルを選択したら、[Execute]ボタンをクリックすれば選択したファイルは multipart/form-data 形式でサーバーに送信され、アクションメソッドの引数に渡されます。
下の Fiddler による要求のキャプチャ画像を見てください。
アクションメソッドへの引数に IFormFile 型の変数を含める方法ですが、下のコード例の SampleA メソッドのように直接含めても、SampleB メソッドのようにモデル経由で含めても、Swagger が自動的にそれを検出してくれます。上の画像は SampleA のものですが、SampleB でも同様になります。
using Microsoft.AspNetCore.Mvc;
namespace WebApi2.Controllers
{
[Route("[controller]")]
[ApiController]
public class UploadController : ControllerBase
{
[HttpPost("SampleA")]
public IActionResult SampleA(IFormFile? postedFile,
[FromForm] string? customField)
{
if (postedFile == null || postedFile.Length == 0)
{
return Content("ファイルを受信できませんでした");
}
if (customField == null)
{
return Content("customField を受信できませんでした");
}
return Content($"ファイル: {postedFile.FileName}, " +
$"customField: {customField} 受信");
}
[HttpPost("SampleB")]
public IActionResult SampleB([FromForm] UploadModels model)
{
if (model.PostedFile == null || model.PostedFile.Length == 0)
{
return Content("ファイルを受信できませんでした");
}
if (model.CustomField == null)
{
return Content("customField を受信できませんでした");
}
return Content($"ファイル: {model.PostedFile.FileName}, " +
$"customField: {model.CustomField} 受信");
}
}
public class UploadModels
{
public string? CustomField { get; set; }
public IFormFile? PostedFile { get; set; }
}
}
この記事の本題とは関係ない話ですが、上のサンプルコードで、SampleA の引数の型、SampleB が使う UploadModels のプロパティの型が null 許容型となっているのには理由がありますのでそれも書いておきます。
ユーザーがファイルを選択しないまま / customFiled が空白のまま[Execute]ボタンをクリックすると、null をアクションメソッドの引数にバインドしようとします。なので、引数を null 許容型にしておかないと、バインド時にエラーとなって HTTP 400 Bad Request が応答として返され、アクションメソッドは実行されません。
上のコード例で言うと、if 文以下は実行されないので期待した応答("customField を受信できませんでした" とか "ファイルを受信できませんでした")は返ってこないということになります。