Home > other >  Not able to update UI after background task completion in my ASP.NET application
Not able to update UI after background task completion in my ASP.NET application

Time:11-24

I am running a long running function as background task in my asp.net application. Before the task completes the main thread exits (I want it that way only, since if I use the await keyword and make main thread wait till background task completes, I get proxy error with message

Proxy Error
The proxy server received an invalid response from an upstream server since the background task is too long

But once after the task completion neither I am able to refresh the page by redirecting to the same page or neither I am able to override the UI. Is there any way to update UI after main thread completes execution.

My code goes like this:

protected void btnImport_Click(object sender, EventArgs e)
{
        var task = ImportThread();

        if (task.IsCompleted)
        {
            DisplaySuccess("Import success");
        }
        else
            DisplayError("Import failed");
}

private async Task<bool> ImportThread()
{
        try
        {
            var success = await Task<bool>.Run(() => new Manager().Import().ConfigureAwait(false);

            if (task.IsCompleted)
            {
                DisplaySuccess("Import success");
            }
            else 
            {
                DisplayError("Import failed");
            }
    
            return true;
}

The above async task awaits the method below which is present in another class.

public bool Import()
{
    // some operations here
    return true;
}

After this method completes the control return backs to ImportThread() but the code written there to override UI is not updating UI. I need to update UI with the status of import. And also from ImportThread control is not going back to button click event method too.

Please help me with any way to update UI the status of import.

Note: I tried using Redirect.Response in ImportThread() to refresh the page, but that didn't work

CodePudding user response:

If you want to asynchronously notify a user (of completion or failure of anything such as a task), you can use web push notification (using firebase messaging cloud) or SignalR sockets. When you use a background task you lose the main thread and unfortunately, there is no way to respond to the related user.

CodePudding user response:

Your problem is that you have to grasp and under stand the web page lifecycle here.

You have this case in which the web page is sitting on the users desktop:

enter image description here

Now say the user clicks a button.

You now have this:

 var task = ImportThread();

    if (task.IsCompleted)

Ok, so the web page is up on the server. You can put in even async awaits until the cows come home, but you STILL HAVE THIS:

enter image description here

So as long as your code runs, or waits, the web page is STILL STUCK UP on the server side. ONLY until code completes and exits does the page travel down to the client side.

AGAIN: Your code behind cannot halt, and cannot wait for something to finish, since if it does, then the page REMAINS up on the server until processing finished.

THEN AND ONLY THEN does the web page make the trip back down to the client side. This then occurs;

enter image description here

And then the SERVER SIDE PAGE IS TOSSED OUT of memory, and all class variables are DESTROYED!!! The web server is now waiting for ANY USER to post back a page for processing!!

So, if you need to run some kind of long running process?

You have a few choices:

post the page, code behind runs, code behind starts a NEW thread, web page makes trip back to client side. At that point, you need a timer some type of web method call (ajax) to poll or ask the server if the long running process is done. And since a ajax call does NOT have use of any web controls on that page, or page class variables (remember, AFTER the web page travels down back to client side, the web page is NOT NOT EXISTING web server side in memory, nor is ANY of the class variables existing). So, again, this quite much means some kind of timer, or as noted, a timer code to call some ajax method. and that long running process will have to VERY likely use session() since you don't have use of controls, or even ViewState.

And you don't necessary have to use a ajax call. You could use a simple JavaScript client side routine with a timer that say clicks a button every 1 or 2 seconds, the code behind runs, and it would then have to get the status of that long running process (again probably from session), and then update the display. And then you could also include code to stop the timer when the status has changed to "done" or whatever.

So code behind does not and will not "update" the web page multiple times. You have ONE round trip, and the code behind must run fast, must finish running, and can't even use a AWAIT command, since then the page will STLL wait, and STILL be stuck up on the server.

If you want to go beyond the simple timer trick approach - which I often use?

Then you need to adopt and introduce into your web site something designed for this type of case -

Thankfully, there is signalR for this purpose, and that no doubt the best option and approach for you, since it is designed for exactly your question and scenario.

SignalR

https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr#:~:text=What is SignalR? ASP.NET SignalR is a library,process of adding real-time web functionality to applications.

  • Related