正在从 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();
});

输出:

进度显示给用户,如下所示,