Response.Flush在异步ASP.NET Web窗体页面中不起作用

问题描述

我正在使用.Net Framework 4.8。 我正在构建一个网页,在单击按钮的PostBack事件后,该网页将重新计算化学制剂的成本,并从sql Server获取数据。然后将计算出的价格存储回sql Server,再通过HttpClient发送到SAP Hana服务器上的REST服务。

由于公式有1000多种(由数千行组件组成,有时会递归包括其他公式),并且必须将价格逐一发布到REST服务,所以我决定使页面成为多线程。

一切正常,我现在能够同时发布数十个价格,并且现在整个过程比同步完成要快得多。我无法做的是向呼叫者网页提供进度反馈。 这是我到目前为止尝试过的:

<%@ Page language="c#" Inherits="..." CodeFile="..." Async="true" AutoEventWireup="true" EnableSessionState="False" %>

在后面的代码中:

protected async void BtUpdatePricesSAP_Click(object sender,EventArgs e)
{
    Response.Write(@"<!DOCTYPE HTML><html><head><title>Price update</title>...");
    Response.Flush();   // Not working!!!
    await ComputeEverything().ConfigureAwait(false);
    Response.Write("<p>Done</p></body></html>");
    Response.End();
}

private async Task ComputeEverything() {
    using var cn = new sqlConnection((string)Application["dataSource"]);
    //await cn.OpenAsync();    <= this does not work,throws an authentication error connecting to the db
    cn.open();

    sqlCommand cmd = new sqlCommand("...",cn);

    using (sqlDataReader dr = await cmd.ExecuteReaderAsync())
    {
        while (await dr.ReadAsync())  { ... }
    
    ...
    // Here I store data in some collections,including a ConcurrentQueue<string> (name FormulationsIndex)
    // and a ConcurrentDictionary (named FormulationRows) containing an array 
    // with the raw materials with quantities and prices.
    }

    // Then,I prepare the threads that will pop the formulations from the queue
    // and call the recursive function that computes the costs:
    
    async void FormulaProcessor()   // local function
    {
        while (FormulationsIndex.TryDequeue(out string formulaCode))
            await ComputeFormulaCostAsync(formulaCode,FormulationRows[formulaCode],1);
    }

    var tasks = new Task[15];
        for (int i = 0; i < tasks.Length; i++)
            tasks[i] = Task.Factory.StartNew(FormulaProcessor);
            
    Task.WaitAll(tasks);

    // here I update price to sql from the ConcurrentDictionary where I stored them

    while (Errors.TryDequeue(out string s))  // Errors is another ConcurrentQueue where I store the errors I found
        Response.Write($"<p>{s}</p>");
}


private async Task<decimal> ComputeFormulaCostAsync(string formulaCode,Formula f,int recursionLevel)
{
    if (Interlocked.Increment(ref processedCount) % 50 == 0)
    {
        int perc = (processedCount * 100 / totalFormulCount);
        Response.Write($"<script>$('#progressBar').text('{perc}%').css('width','{perc}%').prop('aria-valueNow','{perc}');</script>");
        Response.Flush();         ////////////// THIS DOES NOT WORK
        // await Response.FlushAsync();     /////// THIS NEITHER!
    }

    decimal formulaCost = 0;
    ...
    // here I iterate the formula components,calling this function recursively if the component is also a formulation

    // Once done,I update the price of the current formulation in SAP
    SapItemPricesHandler.SapItemPrice ip = new SapItemPricesHandler.SapItemPrice(formulaCost); // helper class to prepare the json for the REST post
    
    var (httpStatusCode,responseContent) = 
        await SessionSL_Async.SendRequest($"Items('{formulaCode}')",new HttpMethod("PATCH"),ip.ToJson()).ConfigureAwait(false);
    // SessionSL_Async is a static class I wrote to handle the REST communications with Hana using HttpClient
    if (httpStatusCode != HttpStatusCode.NoContent)
        Errors.Enqueue($"Errore scrittura prezzo in SAP,formula <b>{formulaCode}</b>,{responseContent}");

    return formulaCost;  // result value helps in recursive formulations,not needed in the main caller
}

我试图尽可能简化代码以使其清晰可见。该页面正常,我在fiddler中看到了Hana的所有帖子。只是,我从Response.Write获得的所有反馈都会在完成所有处理后发生(在我的演示环境中需要几分钟)。我不明白为什么同花顺不起作用。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)