Search code examples
c#asp.netajaxsignalrprogress-bar

How to show an informative real time progress data during long server process


I have a so long process may take 1 hour .

This process consists of many steps run from year to year .My main problem is :

How to provide an informative real time progress to the end user during the process not just a dummy loading bar.

            int index = Convert.ToInt32(e.CommandArgument);
            bool done = false;
            int res = -1;
            int fromVal = int.Parse(gv_balance.Rows[index].Cells[0].Text);
            int toVal = int.Parse(gv_balance.Rows[index].Cells[1].Text);
            int finMonth = 1;
            int finYear = 0;
            int EndServ = 0;
            int calcYear = int.Parse(gv_balance.Rows[index].Cells[2].Text);
            int total;
            total = ((toVal - fromVal) + 1);
            string msg = string.Empty;

            int confirm = Balance.GetConfirmState(calcYear);
            if (confirm == 0)
            {
                RadProgressContext progress = RadProgressContext.Current;
                progress.Speed = "N/A";

                finYear = fromVal;

                for (int i = fromVal; i <= toVal; i++)
                {
                    decimal ratio;
                    //Load New Employees
                    if (toVal - fromVal > 0)
                    {
                        ratio = ((decimal)toVal - i) / (toVal - fromVal) * 100;
                    }
                    else
                    {
                        ratio = ((decimal)toVal - i) / 1 * 100;
                    }
                    progress.PrimaryTotal = total;
                    progress.PrimaryValue = total;
                    progress.PrimaryPercent = 100;

                    progress.SecondaryTotal = 100; // total;
                    progress.SecondaryValue = ratio;//i ;
                    progress.SecondaryPercent = ratio; //i;


                    progress.CurrentOperationText = "Step " + i.ToString();
                    if (!Response.IsClientConnected)
                    {
                        //Cancel button was clicked or the browser was closed, so stop processing
                        break;
                    }

                    progress.TimeEstimated = (toVal - i) * 100;
                    //Stall the current thread for 0.1 seconds
                    System.Threading.Thread.Sleep(100);
                    EndServ = i + 1;
                    if (i == fromVal)
                    {   
                        //--->STEP1
                        //Load intial data 
                        int intial = Balance.PrepareIntialData(calcYear);
                        //--->STEP2
                        res = Balance.CalcEndServed(calcYear, EndServ - 1, 6, 30);

                    }
                     //--->STEP3
                    int newEmps = Balance.PrepareNewEmployees(calcYear, i);

                    for (int j = 0; j < 2; j++)
                    {
                        if (j == 0)
                        {
                            finMonth = 7;
                            finYear = i;

                        }
                        else
                        {
                            finMonth = 1;
                            finYear = i + 1;
                        }
                        //--->STEP4
                        int promotion1 = Balance.PreparePromotionFirst(finYear, finMonth, calcYear);
                         //--->STEP5
                        int promotion2 = Balance.PreparePromotionSecond(finYear, finMonth, calcYear);
                         //--->STEP6
                        int appointment1 = Balance.PrepareAppointmentFirst(finYear, finMonth, calcYear);
                         //--->STEP7
                        int appointment2 = Balance.PrepareAppointmentSecond(finYear, finMonth, calcYear);

                        //--->STEP8
                        int bonus = Balance.PrepareBonus(finMonth, finYear, 0, calcYear);

                         //--->STEP9
                        int salary = Balance.PrepareSalary(finYear, finMonth, calcYear);
                     (((CheckBox)gv_balance.Rows[index].Cells[3].FindControl("chk_redirect")).Checked == true)
                        {
                           //--->STEP9
                            int acco = Balance.PrepareFinanceAccount(finYear, finMonth, calcYear);
                        }

                    }


                    //--->STEP10
                    res = Balance.CalcEndServed(calcYear, EndServ, 6, 30);
                    Balance.CalcStudy(calcYear);
                    UpdateProgressContext();
                    if (res < 0)
                    {

                        success_lb.Visible = false;
                        error_lb.Visible = true;
                        error_lb.Text = "ERROR";

                    }
                    else
                    {
                        done = true;
                        success_lb.Visible = true;
                        error_lb.Visible = false;
                        success_lb.Text = "Success";
                    }


                }
            }

I want to show the current step for example : (Promotion 1 ) in ---> 1-2018 and the percentage of the whole process beside the estimated time .


Solution

  • To report progress of a very long task using signalR you can do something like this (it's only an example to show how it can work):

    Server part

    We start by mapping SignalR.

    public class Startup
    {
       public void Configuration(IAppBuilder app)
       {
           // Any connection or hub wire up and configuration should go here
           app.MapSignalR();
       }
    }
    

    We create a hub class (don't forget to install the signalr package):

    (If you want to report progress to all connected users or a specific group of users take a look here : http://www.asp.net/signalr/overview/guide-to-the-api/working-with-groups)

    In the given example it report progress only to the caller of the Start function.

    public class MyHub : Hub
    {     
        public void Start(string arg)
        {
            Task.Run(() =>
            {
                AVeryLongTask();
            });
        }
    
        //simulate a long task
        void AVeryLongTask()
        {
            for (int i = 0; i < 10000; i++)
            {
                Thread.Sleep(100);              
                Clients.Caller.ReportProgress("AVeryLongTask", i * 100 / 10000);
            }
        }
    }
    

    Client Part

    In the html you must add these references :

    <!--Script references. -->
    <!--Reference the jQuery library. -->
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <!--Reference the SignalR library. -->
    <script src="/Scripts/jquery.signalR-2.0.0.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="/signalr/hubs"></script>
    

    and now the Js part to get the progress from the hub :

     $(function() {
       // Declare a proxy to reference the hub.
       var hub = $.connection.myHub;
       // Create a function that the hub can call to report progress.
       hub.client.reportProgress = function(functionName, progress) {
         $('#progression').append('<li><strong>' + progress + '</strong>:&nbsp;&nbsp;' + functionName + '</li>');
       };
       // Start the connection.
       $.connection.hub.start().done(function() {
         $('#startlongprocess').click(function() {
          //start the long process
           hub.server.start("arg");
           alert("started");
         });
       });
     });
    

    The html container for the progress and the start button :

    <div class="container">    
       <input type="button" id="startlongprocess" value="Send" />
       <ul id="progression"></ul>
    </div>
    

    If you need more explanations don't hesitate to ask.

    ( My example is based on this one http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr from signalr team )