Выполнять тяжелые задачи и сообщать о прогрессе на веб-странице asp.net - PullRequest
0 голосов
/ 07 сентября 2018

У меня есть страница веб-формы asp.net с кнопкой, и при нажатии на нее появляется Task, который должен быть выполнен, я хочу, чтобы задача выполнялась асинхронно и чтобы она сообщала о своем прогрессе File (и возможно позже к интерфейсу, но пока мы придерживаемся файла).

ASPX:

<asp:UpdatePanel runat="server" ID="upPage">
    <ContentTemplate>
        <div class="jumbotron">
            <asp:Button runat="server" ID="BtnExecute" CssClass="btn btn-primary btn-lg" Text="Execute Heavy Task" OnClick="BtnExecute_Click" />
            <asp:Label runat="server" ID="LblStatus" Text="Ready...."/>
        </div>
    </ContentTemplate>
</asp:UpdatePanel>

Код позади:

public partial class _Default : Page
{
    public Progress<int> HeavyTaskProgress { get; set; }
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void BtnExecute_Click(object sender, EventArgs e)
    {
        HeavyTaskProgress = new Progress<int>();
        HeavyTaskProgress.ProgressChanged += Progress_ProgressChanged;
        Task.Run(() => DoProcessing(HeavyTaskProgress)).ContinueWith(t => ProcessingFinished(t));
        LblStatus.Text = "Task is launched.... Please wait";
    }
    private void Progress_ProgressChanged(object sender, int e)
    {
        string message = string.Format("progress at {0}%{1}", e, Environment.NewLine);
        System.IO.File.AppendAllText(@"d:\progress.txt", message);
    }
    private void DoProcessing(IProgress<int> progress)
    {
        for (int i = 0; i < 10; ++i)
        {
            Thread.Sleep(1000); // CPU-bound work
            if (progress != null)
                progress.Report(i);
        }
    }
    private void ProcessingFinished(Task t)
    {
        System.IO.File.AppendAllText(@"d:\progress.txt", "Task done !! " + t.Status);
    }
}

В файле d:\progress.txt у меня есть только одна строка (Задача выполнена ...), и о прогрессе не сообщается (точка останова в Progress_ProgressChanged не прерывается). Я думаю, что это может быть связано с тем, что Progress_ProgressChanged и DoProcessing выполняются в разных потоках, но я не знаю, как это исправить.

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 07 сентября 2018

Я думаю, что ваша проблема в том, что поток, обрабатывающий HTTP-запрос, прерывается при возникновении события.
Объект, подписывающийся на событие, находится в потоке, который отображает страницу. Этот поток завершается после отправки HTTP rsponse обратно в браузер. Поэтому, когда событие происходит, подписчика больше нет.
Поскольку вы должны отправить HTTP-ответ до завершения задачи, если пользователю не нужно ждать завершения задачи, чтобы получить какой-либо отзыв, вам нужно выполнить действие, чтобы записать прогресс в файл в потоке задачи.
Если вам нужна регулярная обратная связь с пользователем, вы можете взглянуть на SignalR.
Вот пример для встраивания кода выполнения записи в задачу:

public class DoingProcessing
{
    public Progress<int> HeavyTaskProgress { get; set; }

    private void Progress_ProgressChanged(object sender, int e)
    {
        string message = string.Format("progress at {0}%{1}", e, Environment.NewLine);
        System.IO.File.AppendAllText(@"d:\progress.txt", message);
    }

    public void DoProcessing()
    {
        HeavyTaskProgress = new Progress<int>();
        HeavyTaskProgress.ProgressChanged += Progress_ProgressChanged;
        DoProcessing(HeavyTaskProgress);
    }
    private void DoProcessing(IProgress<int> progress)
    {
        for (int i = 1; i <= 10; ++i)
        {
            Thread.Sleep(1000); // CPU-bound work
            if (progress != null)
                progress.Report(i*10);
        }
    }

    public void ProcessingFinished(Task t)
    {
        System.IO.File.AppendAllText(@"d:\progress.txt", "Task done !! " + t.Status);
    }
    public DoingProcessing()
    {

    }
} 
...