0

I am using a background worker for a time consuming operation ( To upload some data to server and download some data from server). All server communications are via http requests (GET,POST,PUT,Delete) and the code i used are

private void btnSync_Click(object sender, RoutedEventArgs e)
    {
        btnSync.IsEnabled = false;
        BackgroundWorker syncWorker = new BackgroundWorker();
        syncWorker.WorkerReportsProgress = true;
        syncWorker.WorkerSupportsCancellation = true;
        syncWorker.DoWork+=new DoWorkEventHandler(syncWorker_DoWork);
        syncWorker.ProgressChanged+=new ProgressChangedEventHandler(syncWorker_ProgressChanged);
        syncWorker.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(syncWorker_RunWorkerCompleted);
        syncWorker.RunWorkerAsync();
    }
    private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker target = (BackgroundWorker)sender;
        foreach (...........) // a loop to do some set of actions  on some objects
        {
            target.ReportProgress(1, obj);
            target.ReportProgress(2, obj);
            target.ReportProgress(3, obj);
        }
        target.ReportProgress(4);
    }
    private void syncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (e.ProgressPercentage == 1)
        {  
            string id= e.UserState.ToString(); 
            mySyncHelper.DOGETFROMServer(id); //Issue a GET request and read and process resposne (deserialize json data and insert to local DB)
        }
        if (e.ProgressPercentage == 2)
        {
            string id= e.UserState.ToString(); 
            mySyncHelper.DOGETFROMServer(id);//Issue a GET request and read and process resposne(deserialize json data and insert to local DB)
        }
        if (e.ProgressPercentage == 3)
        {
           string id= e.UserState.ToString(); 
           mySyncHelper.DOGETFROMServer(id);//Issue a GET request and read and process resposne (deserialize json data and insert/Update response data to local DB)
        }
        if (e.ProgressPercentage ==4)
        {
            mySyncHelper.DOPOSTToServer();//Issue a POST request and read and process resposne (deserialize json data and insert/Update response data to local DB)
            mySyncHelper.DOPUTToServer();
            mySyncHelper.DODELETEToServer();
        }
    }
    private void syncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            txtSyncStatus.Visibility = Visibility.Visible;
            txtSyncStatus.Text = string.Concat(DbookLanguage.message_error, Environment.NewLine , e.Error.Message.ToString());
        }
        else
        {
            btnSync.IsEnabled = true;
            txtSyncStatus.Text = "";
        }
    }

The problem i am facing is @ some stages the application is waiting some time for getting response back for the http requests and during this state the entire application goes to freezed state . The code i used for getting response from server is var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); and on this state the application is non responding .

How can i prevent this ? Is any other good way to make series of Http requests and make app UI interactive

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Sebastian
  • 4,625
  • 17
  • 76
  • 145
  • The point of `BackgroundWorker.ProgressChanged` and `BackgroundWorker.RunWorkerCompleted` is that they both run on the thread that started the work (the UI thread). It marshalls back to the UI thread so you can update the screen. However you are doing Blocking IO on your `BackgroundWorker.ProgressChanged`, which is a BIG no no in UX. You should definitely look into `.net 4.5` `async` `await` instead. It is MUCH easier to achieve non-blocking UI. – Aron Feb 14 '14 at 08:46
  • Alternatively you can put each of your `mySyncHelper.DOXXXTToServer()` into its own `BackgroundWorker`. – Aron Feb 14 '14 at 08:47
  • i am restricted to .net 4 only. In my mobile app (.net - 4.5) i am using async await pattern too. So how can i overcome this suituation . I want to make UI interactive while these actions are happening – Sebastian Feb 14 '14 at 08:48
  • HOLY CRAP...I just realised what you are doing. You are using a ThreadPool thread to schedule work onto your UI thread. You've inverted the background work thread pattern. If you did everything in a loop on your UI thread you would actually gain perf, and block for a *slightly* shorter period. – Aron Feb 14 '14 at 08:49
  • I just now realized the wrong thing in code and thanks a lot to figure it out. I slightly change the order like this(http://pastebin.com/q4e0B4R1) and is it ok? – Sebastian Feb 14 '14 at 08:57
  • I still suggest you use `async` `await`. If you only have `.net4`. Microsoft have released a workaround called the `AsyncTargetingPack`. PLEASE use that instead of `BackgroundWorker`. – Aron Feb 14 '14 at 09:00
  • You should do the UI updates on the UI thread and give the user input a priority, possibly like this: http://stackoverflow.com/a/21765205/1768303. Using a background thread only to callback the UI thread will just slow down to the UI. – noseratio Feb 14 '14 at 11:56

1 Answers1

0

As suggested in comments, the code in "ProgressChanged" runs on UI thread which is causing your UI to freeze (because you have server request in this handler).

ProgressChanged 

handler is useful (and should be used) only when you have some regular UI updates (like percentage completed). In your cases, consider moving your entire code to a new method (say GetFromServer(int id)) and make call to this method from inside DoWork. This will cause all this I/O work running on background thread.

Manish Basantani
  • 16,931
  • 22
  • 71
  • 103