Простой BackgroundWorker не обновляет ярлык на веб-странице

Я использовал кусок простого кода из этого полезного сообщение

Он использует кнопку и метку, этикетка должна сообщать "10% завершена"... "20% завершено"... и т.д.

Когда я отлаживаю, код попадает, но мой ярлык не обновляется в браузере.

Я пробовал с и без панелей обновления, с и без главной страницы.

protected void btnStartThread_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }
        });



        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });


        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();

Ответ 1

Вы можете сделать длинный опрос, чтобы получить обновленный результат. Лично я бы не использовал фонового работника в веб-приложении. Кроме того, рассмотрите возможность просмотра SignalR, событий, отправленных сервером, асинхронных и ожидающих или параллельной библиотеки задач.

Ответ 2

BackgroundWorker не подходит для ASP.NET и не очень хорошо работает с ASP.NET, потому что ASP.NET работает с моделью запроса/ответа. Чтобы получать любые обновления, браузеру клиента необходимо запросить информацию с сервера. Например, для обновления Label вам нужно будет отправить запрос на его новое значение на сервер.

Один вариант может использовать AJAX для этой цели на клиенте для обновления страницы. Но вместо использования формального AJAX вы можете использовать iframe, что является отличным способом асинхронного выполнения долгого процесса, не зависящего от какой-либо конкретной структуры AJAX. При нажатии кнопки невидимый iframe динамически генерируется и используется для выполнения LongRunningProcess.aspx в фоновом режиме:

<head runat="server">
<script type="text/javascript">
    function BeginProcess() {
        var iframe = document.createElement("iframe");
        iframe.src = "LongRunningProcess.aspx";
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        document.getElementById('trigger').disabled = true;
    }

    function UpdateProgress(PercentComplete, Message) {
        document.getElementById('<%= Label1.ClientID %>').innerHTML = PercentComplete + '% ' + Message;
}
</script>
</head>

<body>
   <form id="form1" runat="server">
   <div>
    <input type="submit" value="Start Long Running Process" id="trigger" 
       onclick="BeginProcess(); return false;" style="width: 185px;"/>
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
   </div>
   </form>
</body>

И LongRunningProcess.aspx.cs:

protected void Page_Load(object sender, EventArgs e)
{
   for (int i = 1; i <= 9; i++)
   {
       UpdateProgress(i * 10, " Completed.");
       System.Threading.Thread.Sleep(1000);
   }
   UpdateProgress(100, "Finished!");
}

protected void UpdateProgress(int PercentComplete, string Message)
{
    Response.Write(String.Format("<script type=\"text/javascript\">parent.UpdateProgress({0}, '{1}');</script>", PercentComplete, Message));
    Response.Flush();
}

Вы можете увидеть результат, а также прочитать в Dave Ward большую статью здесь:  Простое обновление инкрементного состояния для длинных запросов.

Ответ 3

Редко, но .NET иногда может запускать асинхронные задачи синхронно (это не ясно из документации по MSDN, когда это может произойти), но если это произойдет в вашем случае, это заблокирует цикл сообщений в вашем приложении WinForms.

Чтобы проверить эту теорию, вы можете попробовать добавить вызов Application.DoEvents() в обработчик ProgressChanged и обработчик DoWork и посмотреть, поможет ли это. Это уродливая работа, но она вынуждает пользовательский интерфейс обновляться, если диспетчер выполняет ваши задачи синхронно.

Ответ 4

У вас есть по существу два варианта.

Во-первых, вы можете опросить в браузере таймер, чтобы получить текущий процент, используя JavaScript. setInterval - это очевидный способ использования, и вы можете использовать jQuery или подобное для вызовов AJAX на ваш сервер. Это несколько неэффективно, так как ваш сервер звучит так, как будто он знает, когда он продвигается или делает, поэтому сервер должен поднимать события.

Два, что больше того, что вы хотите, это использовать SignalR. У вас есть вещи, настроенные на "push" с сервера по мере того, как синхронизируются события, но нет простого способа сделать это в HTTP (HTML5 WebSockets также является альтернативой). Использование технологии push-сервера, например SignalR, позволит вам создавать "хабы", которые создают события для клиентов. Они могут быть ориентированными на пользователя целенаправленными событиями или типами всех клиентов - вплоть до вас.

Ознакомьтесь с входом/демонстрацией здесь. Они довольно затруднили задачу: http://www.asp.net/signalr

Также, как упоминалось другими, вы, вероятно, не хотите использовать BackgroundWorker. Попробуйте QueueBackgroundWorkItem. http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx