おそらく、jQuery の ajaxForm() を使用してフォームを送信します。
次に、onSuccess で、さらに AJAX リクエストを開始する関数を呼び出して、JSON を使用して Web サーバーからのアップロードの進行状況をポーリングします。ASP.NET でファイルのアップロードを処理するための URL を用意することとは別に、ある種の非同期ワーカーの進行状況を JSON 形式で返す別の手段も必要になります。
JSON を取得したら、これを jQueryUI プログレス バーにフィードできます。
たとえば、ASP .NET MVC アプリケーションでは、次のようなことを行いました。
ビュー Upload.aspx で、送信を開始します
<% using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data", id = "UploadForm" }))
{ %>
<div>
<input type="file" name="CSVFile" id="CSVFile" />
<button>Upload</button>
</div>
<% } %>
var pb = $('#prog');
var pbContainer = $('#pbcont');
var pbPercent = $('#progp');
var uploadForm = $('#UploadForm');
var status = $('#StatusDetail');
uploadForm.ajaxForm({
iframe: true,
dataType: 'jason',
success: function (data) {
beginProcessing($.parseJSON($(data).text()), '" + Url.Action("UploadStatus", "Upload") + @"', pb, pbContainer, status, pbPercent);
},
error: function (xhr, textStatus, error) {
alert('Error: ' + textStatus);
}
});
初期アップロードを処理するコントローラ メソッド
ここでは、アップロードの開始時に一意の ID を作成しています。これは、後でアップロードの進行状況を知りたいときにアップロードを識別できるようにするためです。
私は、処理を非同期的に処理する、作成したワーカー クラスを使用しています。これは、データベースへのデータの挿入を非同期的に開始する場所です。
このコントローラー メソッドに到達するまでに、FileStream はサーバーに到達している必要があるため、それをワーカーに渡して、ストリームを読み取り、CSV を解析し、データベース作業を行うことができます。ここでは、Worker に StreamReader を渡して、すべてを処理できるようにしていることに注意してください。
// NOTE: The parameter to this action MUST match the ID and Name parameters of the file input in the view;
// if not, it won't bind.
[HttpPost]
public JsonResult Upload(HttpPostedFileBase CSVFile)
{
try
{
if (CSVFile == null || String.IsNullOrWhiteSpace(CSVFile.FileName))
return Json("You must provide the path to your CSV file", "text/plain");
if (!CSVFile.FileName.ToLower().Contains(".csv"))
return Json("You can only upload CSV files", "text/plain");
Guid id = worker.BeginImport(dataReporistory, new StreamReader(CSVFile.InputStream));
//return some JSON
var json = new
{
ID = id,
name = CSVFile.FileName,
size = CSVFile.ContentLength
};
return Json(json, "text/plain");
}
catch (Exception e)
{
return Json(Utilities.DisplayExceptionMessage(e), "text/plain");
}
}
進行状況の更新を返すコントローラー メソッド
[HttpPost]
public JsonResult UploadStatus(Guid id)
{
UploadJob job = Worker.GetJobStatus(id);
return Json(job);
}
プログレスバーの更新を処理するビューの JavaScript
上記のように、ファイルのアップロードが完了すると、 onSuccess イベント中に ajaxForm.Submit() メソッドがここから beginProcessing() を呼び出します。
Upload() コントローラー メソッドから取得した JSON も渡します。これは、ワーカーからジョブの進行状況を取得するときに更新 URL に渡すアップロードの ID をビューに伝えます。
beginProcessing が呼び出されると、進行状況バーをセットアップするための作業が行われますが、基本的には設定されたタイマー間隔で updateProgress() の呼び出しが開始されます。updateProgress は、Web サーバーの UploadStatus ページから JSON をフェッチするすべての作業を行う関数です。
updateProgress が Web サーバーから JSON 更新を取得すると、ページの div に挿入された jQuery UI プログレス バーにそれをフィードするための作業が行われます。
<div id="pbcont">
<p style="display: inline-block;"><strong>Processing...</strong></p>
<h3 style="display: inline-block;" id="progp"></h3>
<div id="prog"></div>
<br />
<div id="StatusDetail"></div>
</div>
function beginProcessing(response, url, pb, pbContainer, statusContainer, pbPercent) {
if (!response.ID) {
alert('Error: ' + response);
return;
}
pb.progressbar({
value: 0
});
pbContainer
.css('opacity', 0)
.css('display', 'block');
//Set the interval to update process.
var hasUpdated = false;
var intervalID = setInterval(function () {
updateProgress(url + '/' + response.ID, pb, statusContainer, pbPercent, intervalID);
}, 500);
}
function updateProgress(url, pb, statusContainer, pbPercent, intervalID) {
//Make an AJAX post to get the current progress from the server
$.post(url,
function (job) {
var newValue = 0;
var currentValue = pb.progressbar('value');
//The percentage value retrived from server:
newValue = (job != null && job.TotalItems != 0 ? (job.ProcessedItems / job.TotalItems * 100) : 0);
if (newValue > 0)
hasUpdated = true;
if (hasUpdated && job == null) {
newValue = 100;
statusContainer.html("<strong>Status:</strong> Finished");
clearInterval(intervalID);
}
if (!hasUpdated)
currentValue = currentValue + 1;
newValue = Math.max(currentValue, newValue);
pb.progressbar("value", newValue);
pbPercent.text(Math.round(newValue, 0) + '%');
if (job != null)
statusContainer.html("<strong>Upload:</strong> " + job.Status);
});
}