WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

MVC でファイルのアップロード

by WebSurfer 3. August 2019 15:58

ASP.NET MVC でファイルをアップロードする方法について書きます。(ダウンロードする方法は先の記事「MVC でファイルのダウンロード」に書きましたのでそちらを見てください)

MVC でファイルのアップロード

普通に form を submit して POST 送信する場合と、jQuery Ajax を利用して非同期で送信する場合の両方の例を紹介します。ちなみに、上の画像は jQuery Ajax を使ってアップロードした結果です。

気をつけるべき点は以下の通りです。

  1. View では form 要素の enctype 属性に "multipart/form-data" が設定されるようにする。
  2. Controller のアクションメソッドでは、アップロードされたファイルがバインドされるパラメータまたはクラスのプロパティは HttpPostedFileBase 型であること。  
  3. 上で述べたバインドされるパラメータまたはクラスのプロパティの名前は、html ソースの <input type="file" ... /> の name 属性と一致させる。
  4. Internet Explorer (IE) でファイルをアップロードすると、クライアント PC でのフルパスがファイル名として送信されることがある(先の記事「IE でアップロードする際のファイル名」を参照)。その場合、HttpPostedFileBase.FieName でファイル名を取得するとクライアント PC でのフルパスになるので、必ず Path.GetFileName を使うこと。  
  5. ワーカープロセスがアップロードするホルダに対する「書き込み」権限を持っていること。
  6. ASP.NET では、デフォルト設定では 4MB を超えるリクエストは送信できないので注意。4MB を超える場合は、web.config の <httpRuntime> セクションの maxLengthRequest の設定で調整できる。

jQuery Ajax を使ってファイルをアップロードする場合は、上記に加えて以下の点に要注目です。

  1. XMLHttpRequest を使用して送信するためのキーと値のペアのセットを取得するために FormData オブジェクトを利用する。詳しくは MDN の記事「FormData オブジェクトの利用」にありますのでそちらを参照してください。
  2. ASP.NET MVC 組み込みの CSRF 防止機能は Ajax でもそのまま使えますので、View での @Html.AntiForgeryToken() と Controller のアクションメソッドへの [ValidateAntiForgeryToken] を忘れずに設定する。

上の画像を表示するのに使ったコードを以下に書いておきます。

Model

public class UploadModels
{
    public string CustomField { get; set; }
    public HttpPostedFileBase PostedFile { get; set; }
}

View

@model Mvc5App.Controllers.UploadModels

@{
    ViewBag.Title = "Upload";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Upload</h2>

@using (Html.BeginForm("Upload", "Home", FormMethod.Post,
                new { enctype = "multipart/form-data" }))
{
    // form 内の隠しフィールドは Ajax でも送信される。
    // なので以下に設定したトークンは送信される。もちろん
    // クッキーのトークンも送信されるので、アクションメソ
    // ッドに [ValidateAntiForgeryToken] を付与すれば
    // CSRF の検証はできる
    @Html.AntiForgeryToken()

    // name 属性はモデルのクラスのプロパティ名と同じにしない
    // とサーバー側でモデルバインディングされないので注意。
    // 大文字小文字は区別しない。
    <input type="file" name="postedfile" />
    <button type="submit">Upload by Submit</button>
    <br />
    @ViewBag.Result
}
<br />
<input type="button" id="ajaxUpload" value="Ajax Upload" />
<br />

<div id="result"></div>


@section Scripts {
  <script type="text/javascript">
    //<![CDATA[
    $(function () {
      $('#ajaxUpload').on('click', function (e) {
        // FormData オブジェクトの利用
        var fd = new FormData(document.querySelector("form"));

        // 追加データを以下のようにして送信できる。フォーム
        // データの一番最後に追加されて送信される
        fd.append("CustomField", "This is some extra data");

        $.ajax({
          url: '/home/upload',
          method: 'post',
          data: fd,
          processData: false, // jQuery にデータを処理させない
          contentType: false  // contentType を設定させない
          }).done(function(response) {
            $("#result").empty;
            $("#result").text(response);
          }).fail(function( jqXHR, textStatus, errorThrown ) {
            $("#result").empty;
            $("#result").text('textStatus: ' + textStatus +
                            ', errorThrown: ' + errorThrown);
          });
      });
    });
    //]]>
  </script>
}

Controler / Action Method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using Mvc5App.Models;
using System.IO;

namespace Mvc5App.Controllers
{
  public class HomeController : Controller
  {
    public ActionResult Upload()
    {
      return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Upload(UploadModels model)
    {
      string result = "";
      HttpPostedFileBase postedFile = model.PostedFile;
      if (postedFile != null && 
          postedFile.ContentLength > 0)
      {
        // アップロードされたファイル名を取得。ブラウザが IE 
        // の場合 postedFile.FileName はクライアント側でのフ
        // ルパスになることがあるので Path.GetFileName を使う
        string filename = 
                  Path.GetFileName(postedFile.FileName);

        // 保存ホルダの物理パス\ファイル名
        string path = Server.MapPath("~/UploadedFiles") + 
                      "\\" + filename;

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

        result = filename + 
                 " (" + postedFile.ContentType + ") - " +
                 postedFile.ContentLength.ToString() + 
                 " bytes アップロード完了";
      }
      else
      {
        result = "ファイルアップロードに失敗しました";
      }

      if (Request.IsAjaxRequest())
      {
        return Content(result);
      }
      else
      {
        ViewBag.Result = result;
        return View();
      }
    }
  }
}

上の例は単一ファイルをアップロードする場合のものです。複数のファイルをアップロードする場合は、例えば html ソースで以下のように name 属性の値に連番で index を付与できれば、

<input type="file" name="postedfiles[0]" />
<input type="file" name="postedfiles[1]" />
 ・・・中略・・・
<input type="file" name="postedfiles[n]" />

Model のクラスを以下のようにして PostedFiles にモデルバインドできます。

public class UploadModels
{
    public string CustomField { get; set; }
    public IList<HttpPostedFileBase> PostedFiles 
    { get; set; }
}

Tags: , , ,

Upload Download

ASP.NET MVC の勉強を始めました

by WebSurfer 16. April 2011 21:51
ASP.NET MVC 実践プログラミング

ASP.NET MVC の勉強を始めました。

リリースされた当初は一時の流行だろうと思っていましたが、バージョン 3 がリリースされるに至って、どうもそうではなさそうな感じがします。

というわけで、時代に取り残されてはいけないと思って(笑)買ったのが左の写真の本です。

ASP.NET(MVC ではない)のいいところは、.NET Framework ベースの Windows アプリケーションの開発経験者には親しみやすいところです。

実際、自分の場合、HTML や JavaScript の知識が全くなかったのですが、Windows アプリケーションを作るときのように Visual Studio でサーバーコントロールをドラッグ&ドロップしてページに貼り付け、ウィザードを使ってプロパティを設定すれば、とりあえず動く Web アプリケーションは簡単に作成できました。

しかし、世の中の主流らしい PHP ベースの Web アプリケーションの開発者にとっては、サーバーコントロール、ポストバック、イベントドリブン、ビューステートなどの ASP.NET 固有の概念は馴染みにくいものだそうです。

それらが使えるから、ASP.NET(MVC ではない)には高い生産性があるのですが、その生産性を捨てても ASP.NET MVC を選ぶだけの理由があるかもしれないと期待しています。

ASP.NET(MVC ではない)の知識も十分でない自分が、余計なものに手を出すべきではないのかもしれませんけどね。

まぁ、Web アプリケーション開発でメシを食っているわけではない自分にとっては所詮趣味の問題に過ぎないので、自己満足でいいんです。(笑)

Tags:

MVC

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  August 2019  >>
MoTuWeThFrSaSu
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar