正在从 ASP.NET Web API 方法向 jquery ajax 发送间歇性响应
Sending intermittent response from ASP.NET Web API method to jquery ajax
我正在执行一项任务,我需要将来自 Web API 方法的间歇性状态响应发送回 jquery ajax 调用并在 [=56= 中显示进度].
最初,jquery ajax 将调用 web Api 方法传递一些参数,然后 web Api 方法开始执行长 运行 操作.每个动作完成后,我想将一个百分比(手动,一些数字)发送回调用 jquery ajax 方法并在 UI、
中显示进度
到目前为止我已经尝试过,
HTML:
<div class="row">
<div class="col-xs-12">
<div class="col-xs-3">
<input type="file" id="FileInput" />
</div>
<div class="col-xs-1">
<button type="button" class="btn btn-default btn-xs" id="UploadFileBtn">Upload</button>
</div>
</div>
</div>
打字稿:
instance.importFile.on('change', function () {
instance.selectedFile = this.files[0];
// This code is only for demo ... (usage of FileAPI)
console.log("name : " + instance.selectedFile.name);
console.log("size : " + instance.selectedFile.size);
console.log("type : " + instance.selectedFile.type);
console.log("date : " + instance.selectedFile.lastModifiedDate);
});
$('#UploadFileBtn').on('click', function () {
var formData = new FormData();
formData.append('file', instance.selectedFile);
$.when(FileUploadService.ProcessData(formData)).done(function () {
}).fail(function () {
}).progress(function () {
console.log("progressing...");
});
});
网页API:
public class FileUploadController : ApiController
{
[HttpPost]
public HttpResponseMessage Upload()
{
if (HttpContext.Current.Request.Files.Count > 0)
{
var postedFile = HttpContext.Current.Request.Files[0];
var fileNameParts = postedFile.FileName.Split('\');
var fileName = fileNameParts[fileNameParts.Length - 1];
fileName = string.Format("{0}_{1}", DateTime.Now.Ticks.ToString(), fileName);
string filePath = Path.Combine("c:\temp", fileName);
postedFile.SaveAs(filePath);
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent("UPLOADED");
System.Threading.Thread.Sleep(5000);
return response;
}
}
问题
现在,我有了网络 api 方法,但是我不确定如何将间歇性响应发送回 UI。我正在寻找简单的解决方案。任何建议/示例表示赞赏。
我遵循了 Jason 的评论,能够使用单独的 ajax 调用进行轮询并获得间歇性响应。
在下面的代码中,我尝试将文件(使用 jquery.form 插件)上传到服务器并在控制器级别执行较长的 运行 任务。为了向用户显示进度,轮询概念用于检查长 运行 任务的状态。
这是代码,
ASP.NET HTML:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div class="row">
<div class="col-xs-12">
<div class="alert alert-warning">This page uses jquery.form plugin to upload</div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="NoFormContentPlaceHolder" runat="server">
<div class="row">
<div class="col-xs-12">
<form id="ImportFileForm" method="post" action="api/FileUpload/Upload" enctype="multipart/form-data">
<div class="col-xs-3">
<input type="file" id="ImportFile" name="ImportFile" accept="*.xlsx" class="col-xs-12 file-selector" />
</div>
<div class="col-xs-1">
<button class="btn btn-danger btn-xs" id="ImportFileBtn" type="submit" title="Import"><span class="glyphicon glyphicon-import"></span>Import</button>
</div>
</form>
</div>
</div>
<div class="row row-margin">
<div class="col-xs-12">
<div class="col-xs-3">
<div id="UploadStatusMessage"></div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
0%
</div>
</div>
</div>
</div>
<div class="col-xs-12">
<div class="alert alert-default" id="PollingStatusMessage"></div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<%:Scripts.Render("~/Scripts/jQueryForm") %>
</asp:Content>
文件上传控制器CS
public class FileUploadController : ApiController
{
[HttpPost] //this is demo, lets assume that user is uploading a file and in the same method, some long running operation is happening.
public HttpResponseMessage Upload()
{
var requestId = HttpContext.Current.Request.Form["RequestTracker"];
if (HttpContext.Current.Request.Files.Count > 0)
{
var postedFile = HttpContext.Current.Request.Files[0];
var fileNameParts = postedFile.FileName.Split('\');
var fileName = fileNameParts[fileNameParts.Length - 1];
fileName = string.Format("{0}_{1}", DateTime.Now.Ticks.ToString(), fileName);
string filePath = Path.Combine("c:\temp", fileName);
postedFile.SaveAs(filePath);
}
//Note: usually, this will be some other operation (database insert/update, data validation etc)
//Inorder to show the exact status / progress, the backend should store some indication which can be retrieved using another ajax call by polling
ObjectCache cache = MemoryCache.Default;
cache.Remove(requestId);//remove any previous for demo purpose
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now.AddMinutes(10);
List<int> taskStatus = new List<int>();
//long running task 1
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 2
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 3
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 4
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
return Request.CreateResponse(HttpStatusCode.OK, "All Operations Completed");
}
}
轮询控制器CS
public class PollingController : ApiController
{
[HttpPost]
public HttpResponseMessage GetStatus(UploadStatusRequest request)
{
ObjectCache cache = MemoryCache.Default;
var fileUploadStatus = cache.Get(request.RequestId) as List<int>;
var count = 0;
if (fileUploadStatus != null)
{
count = fileUploadStatus.Count;
}
return Request.CreateResponse(HttpStatusCode.OK, "Processed data : " + count + ". Please wait...");
}
}
TypeScript 文件:
namespace jQueryForm {
export class FileUploadComponent {
progressBar: JQuery = $('.progress-bar');
importFile: JQuery = $('#ImportFile');
uploadStatusMessage: JQuery = $('#UploadStatusMessage');
pollingStatusMessage: JQuery = $('#PollingStatusMessage');
pollingInstance: any = null;
public RegisterEvents() {
var instance: FileUploadComponent = this;
instance.importFile.on('change', function () {
instance.ResetProgressBar();
});
var requestStatusTracker = null;
$('#ImportFileForm').ajaxForm({
beforeSubmit: function (arr, $form, options) {
requestStatusTracker = new Date().getMilliseconds();
arr.push({ name: 'RequestTracker', value: requestStatusTracker });
return true;
},
beforeSend: function (xhr, options) {
instance.ResetProgressBar();
instance.uploadStatusMessage.text('Uploading...');
},
//Note: The uploadProgress method displays the status of file transfer progress to web api method. Once the file is completely transferred to Web API method,
// the percentage will become 100. But, there could be other operations once the file is reached Web API and those are not counted.
uploadProgress: function (event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
instance.progressBar.css("width", percentVal).attr("aria-valuenow", percentComplete).text(percentVal);
if (percentComplete == 100) {
var uploadStatusRequest = new Entities.UploadStatusRequest();
uploadStatusRequest.RequestId = requestStatusTracker;
instance.Poll(uploadStatusRequest);
instance.uploadStatusMessage.text('File Upload Complete.');
}
},
success: function (data) {
//instance.ResetProgressBar();
//Note: all operations completed in the web api method and the success response is received from the controller
clearTimeout(instance.pollingInstance);
instance.pollingStatusMessage.html(data);
},
error: function (xhr) {
},
complete: function (xhr) {//controller has completed all the action
}
});
}
private ResetProgressBar() {
this.progressBar.css("width", '0%').attr("aria-valuenow", 0).text('0%');
this.uploadStatusMessage.empty();
}
private Poll(uploadStatusRequest) {
var instance: FileUploadComponent = this;
instance.pollingInstance = setTimeout(function () {
$.ajax({
url: "api/Polling/GetStatus", data: uploadStatusRequest, dataType: "json", type: 'POST', success: function (data) {
//Update your status
instance.pollingStatusMessage.html(data);
//Setup the next poll recursively
instance.Poll(uploadStatusRequest);
}, error: function (xhr) {
instance.pollingStatusMessage.html(xhr.responseText);
}
});
}, 2000);
}
}
}
$(function () {
var fileUploadComponent = new jQueryForm.FileUploadComponent();
fileUploadComponent.RegisterEvents();
});
输出:
进度显示给用户,如下所示,
我正在执行一项任务,我需要将来自 Web API 方法的间歇性状态响应发送回 jquery ajax 调用并在 [=56= 中显示进度].
最初,jquery ajax 将调用 web Api 方法传递一些参数,然后 web Api 方法开始执行长 运行 操作.每个动作完成后,我想将一个百分比(手动,一些数字)发送回调用 jquery ajax 方法并在 UI、
中显示进度到目前为止我已经尝试过,
HTML:
<div class="row">
<div class="col-xs-12">
<div class="col-xs-3">
<input type="file" id="FileInput" />
</div>
<div class="col-xs-1">
<button type="button" class="btn btn-default btn-xs" id="UploadFileBtn">Upload</button>
</div>
</div>
</div>
打字稿:
instance.importFile.on('change', function () {
instance.selectedFile = this.files[0];
// This code is only for demo ... (usage of FileAPI)
console.log("name : " + instance.selectedFile.name);
console.log("size : " + instance.selectedFile.size);
console.log("type : " + instance.selectedFile.type);
console.log("date : " + instance.selectedFile.lastModifiedDate);
});
$('#UploadFileBtn').on('click', function () {
var formData = new FormData();
formData.append('file', instance.selectedFile);
$.when(FileUploadService.ProcessData(formData)).done(function () {
}).fail(function () {
}).progress(function () {
console.log("progressing...");
});
});
网页API:
public class FileUploadController : ApiController
{
[HttpPost]
public HttpResponseMessage Upload()
{
if (HttpContext.Current.Request.Files.Count > 0)
{
var postedFile = HttpContext.Current.Request.Files[0];
var fileNameParts = postedFile.FileName.Split('\');
var fileName = fileNameParts[fileNameParts.Length - 1];
fileName = string.Format("{0}_{1}", DateTime.Now.Ticks.ToString(), fileName);
string filePath = Path.Combine("c:\temp", fileName);
postedFile.SaveAs(filePath);
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent("UPLOADED");
System.Threading.Thread.Sleep(5000);
return response;
}
}
问题
现在,我有了网络 api 方法,但是我不确定如何将间歇性响应发送回 UI。我正在寻找简单的解决方案。任何建议/示例表示赞赏。
我遵循了 Jason 的评论,能够使用单独的 ajax 调用进行轮询并获得间歇性响应。
在下面的代码中,我尝试将文件(使用 jquery.form 插件)上传到服务器并在控制器级别执行较长的 运行 任务。为了向用户显示进度,轮询概念用于检查长 运行 任务的状态。
这是代码,
ASP.NET HTML:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div class="row">
<div class="col-xs-12">
<div class="alert alert-warning">This page uses jquery.form plugin to upload</div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="NoFormContentPlaceHolder" runat="server">
<div class="row">
<div class="col-xs-12">
<form id="ImportFileForm" method="post" action="api/FileUpload/Upload" enctype="multipart/form-data">
<div class="col-xs-3">
<input type="file" id="ImportFile" name="ImportFile" accept="*.xlsx" class="col-xs-12 file-selector" />
</div>
<div class="col-xs-1">
<button class="btn btn-danger btn-xs" id="ImportFileBtn" type="submit" title="Import"><span class="glyphicon glyphicon-import"></span>Import</button>
</div>
</form>
</div>
</div>
<div class="row row-margin">
<div class="col-xs-12">
<div class="col-xs-3">
<div id="UploadStatusMessage"></div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
0%
</div>
</div>
</div>
</div>
<div class="col-xs-12">
<div class="alert alert-default" id="PollingStatusMessage"></div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<%:Scripts.Render("~/Scripts/jQueryForm") %>
</asp:Content>
文件上传控制器CS
public class FileUploadController : ApiController
{
[HttpPost] //this is demo, lets assume that user is uploading a file and in the same method, some long running operation is happening.
public HttpResponseMessage Upload()
{
var requestId = HttpContext.Current.Request.Form["RequestTracker"];
if (HttpContext.Current.Request.Files.Count > 0)
{
var postedFile = HttpContext.Current.Request.Files[0];
var fileNameParts = postedFile.FileName.Split('\');
var fileName = fileNameParts[fileNameParts.Length - 1];
fileName = string.Format("{0}_{1}", DateTime.Now.Ticks.ToString(), fileName);
string filePath = Path.Combine("c:\temp", fileName);
postedFile.SaveAs(filePath);
}
//Note: usually, this will be some other operation (database insert/update, data validation etc)
//Inorder to show the exact status / progress, the backend should store some indication which can be retrieved using another ajax call by polling
ObjectCache cache = MemoryCache.Default;
cache.Remove(requestId);//remove any previous for demo purpose
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now.AddMinutes(10);
List<int> taskStatus = new List<int>();
//long running task 1
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 2
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 3
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
//long running task 4
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(100);
taskStatus.Add(i);
}
cache.Set(requestId, taskStatus, policy);
return Request.CreateResponse(HttpStatusCode.OK, "All Operations Completed");
}
}
轮询控制器CS
public class PollingController : ApiController
{
[HttpPost]
public HttpResponseMessage GetStatus(UploadStatusRequest request)
{
ObjectCache cache = MemoryCache.Default;
var fileUploadStatus = cache.Get(request.RequestId) as List<int>;
var count = 0;
if (fileUploadStatus != null)
{
count = fileUploadStatus.Count;
}
return Request.CreateResponse(HttpStatusCode.OK, "Processed data : " + count + ". Please wait...");
}
}
TypeScript 文件:
namespace jQueryForm {
export class FileUploadComponent {
progressBar: JQuery = $('.progress-bar');
importFile: JQuery = $('#ImportFile');
uploadStatusMessage: JQuery = $('#UploadStatusMessage');
pollingStatusMessage: JQuery = $('#PollingStatusMessage');
pollingInstance: any = null;
public RegisterEvents() {
var instance: FileUploadComponent = this;
instance.importFile.on('change', function () {
instance.ResetProgressBar();
});
var requestStatusTracker = null;
$('#ImportFileForm').ajaxForm({
beforeSubmit: function (arr, $form, options) {
requestStatusTracker = new Date().getMilliseconds();
arr.push({ name: 'RequestTracker', value: requestStatusTracker });
return true;
},
beforeSend: function (xhr, options) {
instance.ResetProgressBar();
instance.uploadStatusMessage.text('Uploading...');
},
//Note: The uploadProgress method displays the status of file transfer progress to web api method. Once the file is completely transferred to Web API method,
// the percentage will become 100. But, there could be other operations once the file is reached Web API and those are not counted.
uploadProgress: function (event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
instance.progressBar.css("width", percentVal).attr("aria-valuenow", percentComplete).text(percentVal);
if (percentComplete == 100) {
var uploadStatusRequest = new Entities.UploadStatusRequest();
uploadStatusRequest.RequestId = requestStatusTracker;
instance.Poll(uploadStatusRequest);
instance.uploadStatusMessage.text('File Upload Complete.');
}
},
success: function (data) {
//instance.ResetProgressBar();
//Note: all operations completed in the web api method and the success response is received from the controller
clearTimeout(instance.pollingInstance);
instance.pollingStatusMessage.html(data);
},
error: function (xhr) {
},
complete: function (xhr) {//controller has completed all the action
}
});
}
private ResetProgressBar() {
this.progressBar.css("width", '0%').attr("aria-valuenow", 0).text('0%');
this.uploadStatusMessage.empty();
}
private Poll(uploadStatusRequest) {
var instance: FileUploadComponent = this;
instance.pollingInstance = setTimeout(function () {
$.ajax({
url: "api/Polling/GetStatus", data: uploadStatusRequest, dataType: "json", type: 'POST', success: function (data) {
//Update your status
instance.pollingStatusMessage.html(data);
//Setup the next poll recursively
instance.Poll(uploadStatusRequest);
}, error: function (xhr) {
instance.pollingStatusMessage.html(xhr.responseText);
}
});
}, 2000);
}
}
}
$(function () {
var fileUploadComponent = new jQueryForm.FileUploadComponent();
fileUploadComponent.RegisterEvents();
});
输出:
进度显示给用户,如下所示,