2015-07-10 46 views
3

我正在处理用户可以以excel格式下载数据的任务。 数据是动态生成的(作为通用列表),然后写入excel文件,这是完美的工作。如何检查Web API中的文件下载是否已完成

问题:

我现在面临的问题是,当数据是巨大的,它需要几秒钟下载的文件。在此期间,我需要向最终用户展示某种进步/迹象(比方说,下载....消息)。在当前的代码,我不能够跟踪文件下载完成后...

这里是我的代码

其通过JS代码的Web API方法和搜索条件

var request = {}; 
request.Code = codeDdl.find(':selected').val(); 

$.blockUI({ message: '<h3>Downloading...</h3>' }); 
//Export to Excel all records 
$().largeDownload("api/FileDownload/GetWorkQueueList", { 
    'request': JSON.stringify(request) 
}); 

JS代码读取搜索标准,并将它传递到网络API方法:

(function (d) { 
    d.fn.largeDownload = function (a, b, c) { void 0 !== c ? (c = c.toUpperCase(), "GET" != c && (c = "POST")) : c = "POST"; if (void 0 === b || !1 == b) b = d().parse_url(a), a = b.url, b = b.params; var e = d("<form></form"); e.attr("method", c); e.attr("action", a); for (var f in b) a = d("<input />"), a.attr("type", "hidden"), a.attr("name", f), a.attr("value", b[f]), a.appendTo(e); d("body").append(e); e.bind("submit", DownloadedCallback); e.submit() }; d.fn.parse_url = function (a) { 
     if (-1 == a.indexOf("?")) return { url: a, params: {} }; var b = a.split("?"), a = b[0], c = {}, b = b[1].split("&"), e = {}, d; for (d in b) { 
      var g = 
      b[d].split("="); e[g[0]] = g[1] 
     } c.url = a; c.params = e; return c 
    } 
})(jQuery); 

的Web API

[HttpPost] 
    public HttpResponseMessage GetWorkQueueList() 
    { 
     var resp = new HttpResponseMessage(HttpStatusCode.OK); 
     var currentContext = HttpContext.Current; 

     try 
     { 
      string strRequest = currentContext.Request.Form["request"]; 
      var serializer = new JavaScriptSerializer(); 
      var request = serializer.Deserialize<ViewRequest>(strRequest); 
      request.QueryAllRecords = true; 
      var workQueueList = MappingManager.GetWorkQueueList(request); 

      var legacyExcelView = //get data as generic list 
      .... 
      .... 

      var fileBytes = ExcelManager.GetExcelData<WQExcelView>(legacyExcelView); 
      var stream = new MemoryStream(fileBytes); 
      resp.Content = new StreamContent(stream); 
      resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 
      resp.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "WorkQueueList.xlsx" }; 
      resp.Content.Headers.Add("Content-Encoding", "UTF-8"); 
      return resp; 
     } 
     catch (Exception ex) 
     {     
      resp.Content = new StringContent(ex.Message); 
      return resp; 
     } 
    } 

我已经试过:

在largeDownload javascript函数,我加入这似乎并不像我期望的工作DownloadedCallback。它会在下载完成之前立即被触发。

问:

如何检查是否一个文件下载是Web API方法完成......我应该怎么做,以显示进度条,直到显示文件下载对话框?

回答

0

我们通常用2-3个API调用来解决问题。我们的应用程序是用Java编写的;然而,这里适用相同的基本原则。

第一个调用是在单独的线程中启动大型SQL查询,大型文件创建等。该请求立即返回,有时用id来引用原始请求。

虽然CSV中的行正在写入产生的线程,但我们在原始线程中为处理的行数和总行写入了两个属性值。如果它是一个大SQL语句,我们通常会将语句本身批量处理为几个有限的SQL语句,以便可以逐步设置和显示进度值,而不是一时坐在0%,然后达到100%。分解SQL语句通常只需要几毫秒的额外成本,但在用户体验方面却提供了大量价值。

我们有第二个API调用被轮询,然后返回处理的数量和总数的属性值。这是我们用来激活我们的进度条的动画。当该命令的响应改变达到100%或状态标志发生变化时,我们通常会在单独的API调用中请求完成的文件。您也可以在同一个进度调用中返回文件指针/路径。

+0

感谢您提供一些指导。我不确定我是否能够打破sql语句......我的sql语句非常复杂(连接多个表)并带来大量数据。 –

+0

可以理解。你可能想要知道大部分时间都在哪里。通常,大部分时间都花在SQL调用上。您不必非常多地修改查询 - 您将指定一个限制,然后每次增加起始索引或偏移量以请求下一组行(设置您的进度属性)。 –

+1

此外,它看起来像你使用jQuery - 看看延期对象:https://api.jquery.com/category/deferred-object/。您可以在一个类中包含所有初始和进度请求,并在进度更新和文件完成时通知调用者。 –