メイン画像

ASP.NET MVC - ファイルアップロード(fetch 版)

ASP.NET MVC - ファイルアップロード(fetch 版)


ASP.NET MVC でファイルをアップロードする方法を解説します。

ここでは JavaScript から fetch() を使ってアップロードする方法のみ解説します。
ファイルアップロードの基礎は「ASP.NET MVC でファイルアップロード」を参照してください。

以下の環境で確認しています。

  • .NET Framework 4.6.2
  • AspNet.Mvc 5.2.9

サンプルソース

HTML + JavaScript

<input type="file"> で選択されたファイルを JavaScript から送信します。

fetch() を使って FormData を送るイメージです。

<input type="file" name="uploadFile" />
<input type="button" value="アップロード" />

<script>
  document.addEventListener('DOMContentLoaded', function () {
    // アップロードボタンにクリックイベント追加
    const uploadButton = document.querySelector('input[type="button"]');
    uploadButton.addEventListener('click', function () {
      const formData = new FormData();
      const fileElem = document.querySelector('input[type="file"]');
      formData.append('uploadFile', fileElem.files[0]);
      upload(formData);
    });
  });

  async function upload(formData) {
    try {
      const response = await fetch('/File/Upload', {
        method: 'POST',
        body: formData,
      });

      if (!response.ok) {
        switch (response.status) {
          case 400:
            alert('ファイルを選択してください');
            break;
          default:
            alert('アップロードに失敗しました');
            break;
        }
        return;
      }
      alert('アップロード成功');
    } catch (error) {
      alert('予期せぬエラー');
    }
  }
</script>

アクションメソッド

大枠は form で送る版と大して変わりありません。

View() で HTML を返すのではなく、HttpStatusCodeResult クラスを使ってステータスコードを返すようにしています。

アップロード成功 → 200 OK
アップロードファイル未選択 → 400 Bad Request
例外発生 → 500 Internal Server Error

応答の方法はいろいろあるので、ケースバイケースで試してみればよいかと。
(たとえば Json に処理結果、メッセージを入れて返すなど)

[HttpPost]
public ActionResult Upload(HttpPostedFileBase uploadFile)
{
    // 何も選択せずアップロードされた場合は入力エラー
    if (uploadFile == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    try
    {
        // アップロードされたファイルの保存先を ~/App_Data/Uploaded/[Guid]/元のファイル名 にする
        var path = Path.Combine(Server.MapPath("~/App_Data/Uploaded"),
                                Guid.NewGuid().ToString(),
                                Path.GetFileName(uploadFile.FileName));

        // ディレクトリがなければ作る
        if (!Directory.Exists(Path.GetDirectoryName(path)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(path));
        }

        // アップロードされたファイルを保存する
        uploadFile.SaveAs(path);

        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }
    catch (Exception)
    {
        return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
    }
}

複数ファイルのアップロード

HTML

<input type="file"> に multiple 属性を付けます。

<input type="file" name="uploadFiles" multiple />
<input type="button" value="アップロード" />

FormData に append する部分を、選択されたファイルの数だけ繰り返すようにします。

formData.append('uploadFile', fileElem.files[0]);

for (let i = 0; i < fileElem.files.length; i++) {
  formData.append('uploadFiles', fileElem.files[i]);
}

(補足)ファイルの数だけ FormData に append してください。
次のように fileElem.files をそのまま指定した場合、アクションメソッドの引数の Count は 0 になります。

// ★これは良くない例★
// アクションメソッドにデータが渡されない
// (uploadFiles.Count() が 0 になる)
formData.append('uploadFiles', fileElem.files);

アクションメソッド

form タグで送る版と大差ないです。

仮引数の型をリストにして、リストの件数分、処理を繰り返すだけです。

以下のコードは、アップロードされたファイルすべてを Web アプリルートの App_Data/Uploaded/[Guid] フォルダに元のファイル名で保存します。

[HttpPost]
public ActionResult Upload(IEnumerable<HttpPostedFileBase> uploadFiles)
{
    // 何も選択せずアップロードされた場合は入力エラー
    if (uploadFiles == null || !uploadFiles.Any())
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    // アップロードされたファイルの保存先を ~/App_Data/Uploaded/[Guid] フォルダにする
    var folderPath = Path.Combine(Server.MapPath("~/App_Data/Uploaded"),
                                  Guid.NewGuid().ToString());

    // フォルダがなければ作る
    if (!Directory.Exists(folderPath))
    {
        Directory.CreateDirectory(folderPath);
    }

    // アップロードされたファイルすべてを、所定のフォルダに元のファイル名で保存する
    foreach (var file in uploadFiles)
    {
        file.SaveAs(Path.Combine(folderPath, Path.GetFileName(file.FileName)));
    }

    return new HttpStatusCodeResult(HttpStatusCode.OK);
}

アカウントを作成 して、もっと沢山の記事を読みませんか?


この記事が気に入ったら ことりと さんを応援しませんか?
メッセージを添えてチップを送ることができます。


この記事にコメントをしてみませんか?


酒とアクアリウムが最近の楽しみ。

おすすめの記事