ASP.Net页面上长时间运行任务的用户反馈实现

在开发过程中,经常会遇到需求变更的情况。本文将介绍一个在ASP.Net页面上实现对长时间运行任务的用户反馈的解决方案。这个方案是在系统需求变更后提出的,原本系统是一个简单的内部网页面,用于展示报告并提供数据过滤和排序的功能。变更后的需求是允许用户将报告的底层数据保存为XML文档,以便离线使用。如果这个需求在项目初期就被提出,那么解决方案的架构可能会有所不同。

问题在于,需要让用户知道服务器上确实有任务在执行,而这个任务可能需要几分钟才能完成。考虑过显示进度条、沙漏图标或者异步执行任务并让用户刷新页面以获取更新,但这些方案都不尽人意。由于服务器任务无法向客户端(浏览器)推送状态更新,解决方案是让浏览器定期从服务器请求更新。

简而言之,选择的解决方案是异步执行长时间运行的任务,并在浏览器请求的单独线程上监控它。在实践中,长时间运行的任务会将进度更新写入共享区域,而网页会定期请求服务器以读取该共享区域并显示进度给用户。

使用代码

下面是一个简化版的解决方案,用于演示原理。有一个名为Default.aspx的网页,上面有一个按钮,用于触发长时间运行的服务器任务。这个任务在服务器端部署为一个通用处理器,ProcessTask.ashx。当按钮被点击时,Javascript会被触发,如下所示:

var tmrProgress; // SENDING XML function postSend() { var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); divResponse.innerHTML = ""; xmlhttp.open("POST", "ProcessTask.ashx", true); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) { window.clearInterval(tmrProgress); var response = xmlhttp.responseText; divResponse.innerHTML += response; } }; xmlhttp.send(); tmrProgress = window.setInterval("showSendProgress();", 500); }

Javascript发起异步请求到处理器,注册任务完成的回调,并启动一个计时器,定期从服务器请求进度更新。

为了测试目的,服务器任务通过thread.sleep命令模拟创建文件所花费的时间。在“提交”每个文件时,计数会增加并保存到共享区域,这里使用的是.NET缓存。

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest Const NumberOfFilesToSend As Integer = 50 context.Response.ContentType = "text/plain" Try For i As Integer = 1 To NumberOfFilesToSend context.Cache("FileSending") = i Threading.Thread.Sleep(100) Next context.Response.Write(String.Format("Finished sending {0} files", NumberOfFilesToSend)) Catch ex As Exception context.Response.Write(String.Format("Error sending files: {0}", ex.Message)) End Try End Sub

进度报告是通过浏览器上500毫秒间隔调用的showSendProgress()函数实现的,这个函数调用一个单独的通用处理器来获取服务器的当前状态:

function showSendProgress() { var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.open("POST", "GetTaskProgress.ashx", true); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) { var response = xmlhttp.responseText; divResponse.innerHTML = "Processing File: " + response; } }; xmlhttp.send(); }

GetTaskProgress.ashx处理器的响应被捕获在回调中,并在页面上更新状态,divResponse中显示。GetTaskProgress.ashx简单地查询缓存并报告回客户端:

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest context.Response.ContentType = "text/plain" If Not HttpContext.Current.Cache("FileSending") Is Nothing Then context.Response.Write(HttpContext.Current.Cache("FileSending")) End If End Sub

解决方案的一个重点是,它并不准确地实时报告服务器任务的确切状态,它只是定期向用户指示有事情在进展。根据任务的持续时间,可能需要对刷新率进行一些微调,以及它更新自身状态的频率。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485