使用window.location之后,异步功能将作为同步功能

时间:2020-05-06 09:44:06

标签: javascript c# ajax asynchronous

我从事一个ASP.NET MVC 4项目,用户可以在UI上应用过滤器并提取Excel报告。数据存储在MS SQL server中。为了提高性能,我决定在应用程序中采用async

  1. 减少提取时间
  2. 允许用户进行并行提取

为此,我的方法是:

  1. 当用户单击UI上的提取按钮->客户端将调用ajax到服务器上的async函数->此async函数将依次创建一个Command对象并执行ExecuteReaderAsync()。使用此DbDatareader通过NPOI生成Excel文件,并将文件内容保存到TempData。检索文件的处理程序将返回客户端,以供以后使用window.location下载。我从这篇帖子Download Excel file via AJAX MVC

  2. 中采用了这些技术
  3. 第一次提取后,如果用户要并行提取另一个数据集,则可以再次单击提取按钮,应用程序将重复步骤1。

结果是可以同时进行2次或更多次数据提取。

我的问题是,例如,当前并行运行的4个提取,如果其中任何一个提取完成并下载了1个文件(使用window.location)。下次用户单击提取按钮(重复步骤1)时,它将不再同步,以后的提取将等待上一次提取完成后再执行。

在调试时,如果我重新启动ISS服务器,该问题会持续一会儿,直到下载1个文件为止,因此我怀疑window.location所做的事情会在下载任何文件时阻塞服务器上的线程。

更新1

班级:

public class QUERYREADER
{
    public DbConnection   CONNECTION { get; set; }
    public DbDataReader   READER { get; set; }
}

型号:

public async Task<QUERYREADER> GET_DATA(CancellationToken ct)
{
    //Create the query reader
    QUERYREADER qr  = new QUERYREADER();

    //Set up the database instances
    DbProviderFactory dbFactory = DbProviderFactories.GetFactory(db.Database.Connection);

    //Defined the query
    var query = "SELECT * FROM Table";

    //Set up the sql command object
    using (var cmd = dbFactory.CreateCommand())
    {
        //Try to open the database connection 
        try
        {
            //Check if SQL connection is set up
            if (cmd.Connection == null)
            {
                cmd.CommandType = CommandType.Text;
                cmd.Connection  = db.Database.Connection;
            } 
            //Open connection to SQL if current state is closed
            if (cmd.Connection.State == ConnectionState.Closed)
            {
                //Change the connection string to set the packet size to max. value = 32768 to improve efficiency for I/O transmit to SQL server 
                cmd.Connection.ConnectionString = cmd.Connection.ConnectionString + ";Packet Size=20000";
                //Open connection
                await cmd.Connection.OpenAsync(ct);
            }
            //Save the connection 
            qr.CONNECTION = cmd.Connection;

        } catch (Exception ex) {
            //If errors throw, close the connection
            cmd.Connection.Close();
        };


        //Retrieve the database reader of provided sql query
        cmd.CommandText = query;       
        DbDataReader dr = await cmd.ExecuteReaderAsync(ct);
        qr.READER.Add(dr);       
    }  

    //Return the queryreader
    return qr;
}

控制器:

  public async Task<JsonResult> SQL_TO_EXCEL()
  {        
       //Set up the subscription to client for "cancellation request, browser closing"
        CancellationToken   disToken = Response.ClientDisconnectedToken;             

        //Get the datareader
        try 
        {
            qr  = await GET_DATA(disToken);        
        } 
        catch(Exception ex) { }

        //Open the connection to SQL server
        using (qr.CONNECTION)
        {
            using (var dr = qr.READER)
            {                                            
                while (await dr.ReadAsync(disToken))
                {
                    for (int k = 0; k < dr.FieldCount; k++)
                    {
                        //.... using NPOI to write Excel file to MemoryStream
                    }
                }
                dr.Close();
            }
        }

        //Generate XL file if controller action is still running (no "cancellation request, browser closing")
        if (!disToken.IsCancellationRequested)
        {

            string file_id = Guid.NewGuid().ToString();
            //... Write the NPOI excel file to TempData and then create a handler for later download at client
            //This line caused trouble
            TempData["file_id"] = XLMemoryStream.ToArray();

            HANDLER["file_id"]      = file_id;
            HANDLER["file_name"]    = FILE["FILE_NAME"].ToString().NonUnicode() + FILE["FILE_TYPE"].ToString() ;
        }

        //Return JSON to caller
        var JSONRESULT                  = Json(JsonConvert.SerializeObject(HANDLER), JsonRequestBehavior.AllowGet);
            JSONRESULT.MaxJsonLength    = int.MaxValue;

        return JSONRESULT;
  }

    public async Task<ActionResult> DOWNLOAD_EXCEL(string file_id, string file_name)
    {
        if (TempData[file_id] != null)
        {
            byte[] data = await Task.Run(() => TempData[file_id] as byte[]);
            return File(data, "application/vnd.ms-excel", file_name);
        }
        else
        {
            return new EmptyResult();
        }
    }   

JavaScript

    $.ajax({
        type: 'POST',
        async: true,
        cache: false,
        url:  'SQL_TO_EXCEL',
        success: function (data)
        {
            var response = JSON.parse(data);
            window.location =
            (
                "DOWNLOAD_EXCEL"    +
                '?file_id='         + response.file_id +
                '&file_name='       + response.file_name
            );
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            console.log(errorThrown);
        }
    });    

更新2:

经过大量测试,我发现window.location与服务器上的线程无关,行TempData[file_id] = XLMemoryStream.ToArray()引起了问题。看来问题与本帖子Two parallel ajax requests to Action methods are queued, why?

中所述的问题类似

0 个答案:

没有答案