よくある 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 Task Post(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 が勝手にエスケープ処理をしてしまい、サーバー側で正しくデータを受け取れません。
参考記事