ASP.NET Core(.NET 6)のWEB APIで、JSONとファイルを同時にPOSTリクエストされたとき、そのJSONに対応するモデルクラスに正しく値をバインドする方法を解説していきます。
JSON+ファイルのPOSTリクエスト
JSONのみのPOSTリクエスト をWEB API側のアクションで受け付ける場合、
ASP.NET Core (.NET 6) では、JSONの内容がアクションの引数に設定したモデルクラスに対応していたとき、JSONの値を自動的にモデルクラスにバインドしてくれます。
このときのPOSTで送信されるJSONのMIMEタイプ(Content-Type)は「application/json」となっています。
以下がJSONのみのPOSTリクエスト用のアクションメソッドの例です。
この例ではLoginアクションメソッドの引数に設定しているUserモデルクラスにJSONの値がバインドされるようになっています。
// POSTアクションメソッド
// POST: api/User/login
[HttpPost("login")]
public ActionResult Login([FromBody] User user)
{
// 処理を書く
return Ok();
}
// Userモデルクラス
public class User
{
// ユーザー名
public string UserName { get; set; }
// パスワード
public string Password { get; set; }
}
それでは、JSONとファイルを一緒にPOSTで送信する場合も自動的にモデルにバインドされるかというと、そうでもありません。
JSONと同時にファイルをアップロードする場合、上記のJSONのみのときのようにJSONをモデルに自動的にバインドすることができなくなっています。
これは、ファイルをアップロードする場合は、POSTリクエストのMIMEタイプは「mulitpart/form-data」とする必要があり、ASP.NET 側ではファイルと一緒に送信するJSONを正しくJSONであると判別することができないことが原因となっています。
次の見出しでは、JSON+ファイルをPOST送信する場合にJSONを用意したモデルクラスにバインドする実装について解説していきます。
JSON+ファイルのPOSTリクエスト 実装方法
JSON+ファイルをPOST送信する場合にJSONを用意したモデルクラスにバインドするには、カスタムしたモデルバインダーを実装する必要があります。
モデルバインダーは、HTTPリクエストから受信したデータをASP.NET Coreのモデルにバインドするために使用されます。
そしてこのモデルバインダーをカスタムして、multipart/form-data形式でJSONデータを受け取り、指定されたデータ型にバインドするための実装をしていく必要があります。
以下がカスタムモデルバインダーの実装例になります。
// モデルバインダー(IModelBinder) を実装
public class JsonWithFilesFormDataModelBinder : IModelBinder
{
// bindingContext:バインド対象の値、バインド先のデータ型、およびバインドの構成情報
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
// バインド対象のパラメーター名
string fieldName = bindingContext.FieldName;
// パラメーターの値を取得
var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);
// バインドされた値がない場合、処理終了
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
else
{
// バインドされた値を格納
bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);
}
// バインドされた値を取得
string value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
try
{
// JSONデータを指定されたデータ型にデシリアライズ
object result = JsonConvert.DeserializeObject(value, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(result);
}
catch (JsonException)
{
// 失敗した場合 バインド失敗のリザルトを返す
bindingContext.Result = ModelBindingResult.Failed();
}
// 成功した場合 バインド成功のリザルトを返す
return Task.CompletedTask;
}
}
ASP.NET おすすめ入門講座
3つのWebアプリケーションの開発を通して、ASP.NETについて基礎から学べるおすすめの入門講座がこちら☟
【入門者向け】ASP.NET MVCでWebアプリ開発のノウハウを学ぼう!