如何在Web API中检查文件下载是否完成

3
我正在处理一个任务,用户可以下载Excel格式的数据。数据是动态生成的(作为通用列表),然后写入Excel文件,这部分代码完美运行。
问题是当数据很大时,下载文件需要几秒钟的时间。在此期间,我需要向最终用户显示某种进度/指示(例如,“正在下载…”消息)。使用当前的代码,我无法跟踪文件下载何时完成...
以下是我的代码:
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)
});

读取搜索条件并将其传递给Web API方法的JS代码:

(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 方法中检查文件下载是否完成... 我应该做什么来显示进度条,直到文件下载对话框出现?

1个回答

0

通常我们通过2-3个API调用来解决问题。我们的应用程序是用Java编写的,但是基本原理在这里同样适用。

第一次调用是为了在一个独立线程中启动大型SQL查询、大文件创建等操作。该请求会立即返回,有时还会返回一个用于引用原始请求的ID。

在生成的线程中写入CSV行时,我们在原始线程中写入两个属性值,分别表示已处理的行数和总行数。如果是一个大型SQL语句,我们通常将语句本身分批拆分成几个有限的SQL语句,以便可以逐步设置进度值并显示,而不是在一段时间内停留在0%,然后突然跳到100%。拆分SQL语句通常只增加几毫秒的成本,但在用户体验方面提供了很多价值。

我们有第二个API调用,用于轮询并返回已处理和总计数的属性值。这是我们用来制作进度条动画的数据。当进度达到100%或者该调用的响应中的状态标志发生变化时,我们通常会通过另一个API调用请求完成的文件。你也可以在同一个进度调用中返回文件指针/路径。


感谢提供一些方向。我不确定能否分解SQL语句...我的SQL语句非常复杂(连接了多个表)并且带来了大量数据。 - JGV
可以理解。你可能想要分析当前大部分时间花在哪里。通常,大部分时间都花在 SQL 调用上。你不需要修改查询太多——你只需要指定一个限制,然后每次增加起始索引或偏移量来请求下一组行(在执行时设置进度属性)。 - Ryan Neuffer
1
另外,看起来你正在使用jQuery - 看一下Deferred对象:https://api.jquery.com/category/deferred-object/。你可以将所有的初始和进度请求包含在一个单独的类中,并在有进度更新和文件完成时通知调用者。 - Ryan Neuffer
好的,我会查看延迟对象。 - JGV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接