Question

Yo, i have created a WebProject to test if its possible to create a asyncTask to update a Progressbar:

public partial class AsyncTest : System.Web.UI.Page
{
    private String _taskprogress;
    private AsyncTaskDelegate _dlgt;
    protected delegate void AsyncTaskDelegate();

    protected void Page_Load(object sender, EventArgs e)
    {
    }

    public String GetAsyncTaskProgress()
    {
        return _taskprogress;
    }

    public IAsyncResult OnBegin(object sender, EventArgs e,
       AsyncCallback cb, object extraData)
    {
        _taskprogress = "AsyncTask started at: " + DateTime.Now + ". ";

        _dlgt = new AsyncTaskDelegate(ReadFile);
        IAsyncResult result = _dlgt.BeginInvoke(cb, extraData);

        return result;
    }

    public void ReadFile()
    {
        try
        {
            string Filename = @"D:\Material.txt";
            int filelength = TotalLines(Filename); //just reads the lines of the file

            ProgressBar1.Maximum = filelength;

            using (StreamReader reader = new StreamReader(Filename))
            {
                string line;
                int actualfileline = 1;
                while ((line = reader.ReadLine()) != null)
                {
                    string test = line;
                    ProgressBar1.Value = actualfileline;
                    actualfileline++;
                    //UpdatePanel1.Update(); <- Doesnt work
                    System.Threading.Thread.Sleep(5);
                }
            }
        }
        catch (Exception ex)
        {
            string exm = ex.Message.ToString();
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        OnBegin(this, null, null, null);

    }
}

Aaaand my aspx-code: (i have a scriptmanager for sure also)

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:Button runat="server" ID="btnDoTask" Text="Do Task" OnClick="Button1_Click" />
        <br />
        <br />
        <eo:ProgressBar ID="ProgressBar1" runat="server" Width="250px" 
            BackgroundImage="00060301" BackgroundImageLeft="00060302" 
            BackgroundImageRight="00060303" ControlSkinID="None" IndicatorImage="00060304">
        </eo:ProgressBar
    </ContentTemplate>
</asp:UpdatePanel>

Calling the Updatepanel1.Update() doesnt work, because it says:

You can only call the Update-methoe bevor rendering

So how else can i update it then ? I want the user to see the progress on the progressbar - because i want to implement a bigger file-reading piece of code. Im really new to async-programming, so im not sure if there is everything you need :/

Edit:

Okay, now I created a Webservice in my page:

[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public string GetProcess()
{
    if (actualfileline != null)
    {
        return actualfileline.ToString();
    }
    else
    {
        return "0";
    }
}

And i want to call it trough my Button:

<asp:Button runat="server" ID="btnDoTask" Text="Do Task" OnClick="Button1_Click" OnClientClick="StartJavaScriptProgress()" />

The javascript-part:

function StartJavaScriptProgress()
{
    var elm = document.getElementById("LabelProgress");
    elm.innerText = "Currently Working ...";
    setTimeout(WebService(), 1000);
};

function WebService() {
    $.ajax(
    {
        type: "POST",
        url: "AsyncTest.aspx/GetProcess",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            alert("Worked");
            var elm = document.getElementById("ProgressBar1");
            elm.value = response.d; 
        },
        error: function (jqXHR, textStatus, errorThrown) {

            alert("Error starting process");
        }
    })
};

But it doesnt work ...

Was it helpful?

Solution

Reading a file synchronously on another thread will not improve the performance of your web app, check this for more details. Instead, you should be using a naturally asynchronous API like ReadLineAsync, and enable asynchronous completion of the HTTP request with RegisterAsyncTask, like this:

// Make sure to enable asynchronous request processing:
// <%@ Page Async="true" ... %>

public partial class AsyncTest : System.Web.UI.Page
{
    private String _taskprogress;

    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        RegisterAsyncTask(new PageAsyncTask(ReadFileAsync));
    }

    public async Task ReadFileAsync()
    {
        try
        {
            string Filename = @"D:\Material.txt";
            int filelength = TotalLines(Filename); //just reads the lines of the file

            ProgressBar1.Maximum = filelength;

            using (StreamReader reader = new StreamReader(Filename))
            {
                string line;
                int actualfileline = 1;
                while ((line = await reader.ReadLineAsync()) != null)
                {
                    string test = line;
                    ProgressBar1.Value = actualfileline;
                    actualfileline++;
                    //UpdatePanel1.Update(); <- Doesnt work
                    System.Threading.Thread.Sleep(5);
                }
            }
        }
        catch (Exception ex)
        {
            string exm = ex.Message.ToString();
        }
    }
}

Note, this still won't update the progress UI in the client side page. What this does is making the current HTTP request to finish asynchronously on the server side. The browser will still be waiting for it. This improves the scalability of your web app, but the web page on the client side will be rendered only when ReadFileAsync has been fully completed.

If you want to provide the progress updates on the client side, you should use AJAX and start the above lengthy process via XHR request, or inside a hidden frame. You would then be able to track its progress with a secondary XHR request and update the UI. Inside ReadFileAsync, you'd need to keep the progress info inside a session variable, e.g. Session["actualfileline"] = actualfileline. You'd access Session["actualfileline"] from your secondary XHR requests.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top