よくある Webページ上に ファイル を ドラッグ & ドロップ して アップロード する アプリ を作ってみます。 この記事では サーバー側 と クライアント側 をまとめて掲載しています。 サーバー側は ASP.NET WebAPI、クライアント側は HTML + JavaScript で実装します。 アップロード は POST で フォームデータ として アップロード します。
目次
サンプルコード
サーバー処理
WebAPI 用 の コントローラ を作成します。 受け取る ファイルデータ は フォームデータ として受け取ります。 同じファイル名をアップロードするとエラーになる点にご注意ください。。
FileController.cs
using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; public class FileController : ApiController { // POST api/<controller> public async TaskPost(bool overwrite = false) { var tempPath = Path.GetTempPath(); var provider = new MultipartFormDataStreamProvider(tempPath); await this.Request.Content.ReadAsMultipartAsync(provider); foreach (var file in provider.FileData) { // アップロードファイル名の取得 var fileName = file.Headers.ContentDisposition.FileName; fileName = fileName.StartsWith("\"") || fileName.StartsWith("'") ? fileName.Substring(1, fileName.Length - 1) : fileName; fileName = fileName.EndsWith("\"") || fileName.EndsWith("'") ? fileName.Substring(0, fileName.Length - 1) : fileName; fileName = Path.GetFileName(fileName); // ファイルの移動 File.Move(file.LocalFileName, Path.Combine("D:\\", fileName)); } return this.Request.CreateResponse(HttpStatusCode.OK); } }
クライアント処理
記述する部分としては HTML、CSS、JavaScript があるので、それぞれ順に説明していきます。
HTML
まずは html について。 ファイルアップロード に関して html で気にするとすれば ドラッグ&ドロップ をどの領域で受け付けるか、と言ったところでしょうか。 今回は ブラウザページ全体 (body) で受け付けるようにしたいと思います。
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Index - My ASP.NET Application</title> <link href="/Content/Site.css" rel="stylesheet" type="text/css" /> <link href="/Content/bootstrap.min.css" rel="stylesheet" type="text/css" /> <script src="/Scripts/library/modernizr-2.6.2.js"></script> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">Application name</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> </ul> </div> </div> </div> <div class="container body-content"> <h2>Index</h2> <div id="msg"></div> <hr /> <footer> <p>© 2015 - My ASP.NET Application</p> </footer> </div> <script src="/Scripts/library/jquery-1.10.2.min.js"></script> <script src="/Scripts/library/bootstrap.min.js"></script> <script type="text/javascript" src="/Scripts/Home/index.js"></script> </body> </html>
CSS
ドラッグ & ドロップ の 領域 を 画面全体 としたい場合、 html と body に対して width: 100%; height: 100%; を指定します。 この指定をしておかないと、画面全体ではなく指定された領域のみでしかファイルアップロードが受け付けられません。 (意図的に場所指定したいのであれば問題ないですが…)
Site.css
html, body { width: 100%; height: 100%; }
JavaScript
Webページ に ファイル が ドラッグ&ドロップ で落とされたとき、ファイルを受け取ってサーバーへ投げつける処理を記載します。 ポイントはいくつかあるのですが…まずはサンプルコードを掲載して、サンプルコードのあとに解説を載せます。
index.js
/** * 指定されたファイルをアップロードします。 * @param {FileList} files アップロードするファイルリスト */ var upload = function (files) { var i, formData; // アップロード用のデータを生成 formData = new FormData(); for (i = files.length; i--;) { formData.append('files', files[i]); } // ファイルアップロードの実行 $.ajax({ url: '/api/file?overwrite=true', method: 'POST', processData: false, contentType: false, data: formData }).done(function (data, textStatus, jqXHR) { $('#msg').append(JSON.stringify(data)); }).fail(function (jqXHR, textStatus, errorThrown) { $('#msg').append(textStatus); }); }; /** * 指定されたファイルを画面に表示する。 * @param {FileList} files 読み取るファイルリスト */ var read = function (files) { var fragment, i, item; fragment = document.createDocumentFragment(); for (i = files.length; i--;) { item = document.createElement('div'); item.appendChild(document.createTextNode(files[i].name)); fragment.appendChild(item); } $('#msg').append(fragment); }; /** * dragover イベント が発生したとき呼び出されます。 * @param {Event} event イベントオブジェクト */ var body_ondragover = function (event) { event.preventDefault(); $('#msg').text('ondragover'); }; /** * drop イベント が発生したとき呼び出されます。 * @param {Event} event イベントオブジェクト */ var body_ondrop = function (event) { var i, files, fragment, item; $('#msg').text('ondrop'); files = event.originalEvent.dataTransfer.files || []; read(files); upload(files); }; /** * ドキュメント生成が完了したとき呼び出されます。 */ var document_onready = function (event) { $(window.document.body).on( 'dragover', body_ondragover ).on( 'drop', body_ondrop ); }; $(document).ready(document_onready);
ドラッグ & ドロップ イベント
ドラッグ&ドロップ 関連のイベントは以下の通りです。
このうち ファイルアップロード に関連するのは ondragover
と ondrop
。
- ondragstart
- ondrag
- ondragend
- ondragenter
- ondragover
- ondragleave
- ondrop
ファイルアップロードに関する ondragover
と ondrop
には以下のような処理を記述します。
- ondragover
- preventDefault で デフォルト機能を無効化
- ondrop
- 実際の ドロップ処理 を実装
ドロップされたファイル情報の取得
ファイルドロップ された際、File オブジェクト
を利用して ドロップ された ファイル情報 を取得します。
jQuery で File オブジェクト
へ アクセス するためには、以下のように オリジナル の イベントオブジェクト からたどるようにします。
event.originalEvent.dataTransfer.files[i]
File オブジェクト
には以下のようなプロパティ、メソッドがあるようです。
File オブジェクト
- プロパティ
lastModifiedDate
name
isClosed
size
type
- メソッド
close()
slice([start[, end[, contentType]]])
Ajax で ファイルアップロード
ファイルアップロードには File オブジェクト
から取得される情報を FormData オブジェクト
に詰め込んだものを 送信 します。
また、 jQuery を用いて送信する場合、 processData: false
と contentType: false
を指定します。
これらの指定をしておかないと、 jQuery が勝手にエスケープ処理をしてしまい、サーバー側で正しくデータを受け取れません。
参考記事
- w3schools.com - ondrop Event
- MDN - FileReader
- しばやん雑記 - ASP.NET Web API でアップロードされたファイルを扱う方法を知らなかったので調べた
- しばやん雑記 - HTML5 の Drag and Drop API と File API を使ってファイルアップロードを実装する
- CODE PROJECT - Web API Thoughts 1 of 3 - Data Streaming
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!