Problem
 
UAB does not resume
broken downloads (due to connection failure or user cancelling the
download).
 
Solution
 
These are the two
changes to do in the BitsDownloader class
 
1. On the
OnJobError method we need to NOT cancel the BITS job if the state is
ERROR:
 
if( state !=
BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED &&
     state !=
BG_JOB_STATE.BG_JOB_STATE_CANCELLED &&
     state !=
BG_JOB_STATE.BG_JOB_STATE_TRANSFERRING &&      // don’t interrupt
downloads in progress
     state != BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED
&&      // don’t cancel a finished download
     state !=
BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR &&   // don’t cancel when
connection problems
     state != BG_JOB_STATE.BG_JOB_STATE_ERROR )
{            // don’t cancel when connection problems
    
pJob.Cancel();
 }
 
2. On the
CheckForResumeAndProceed method check to see if the job is in ERROR or
TRANSIENT_ERROR state and resume it. Why add this here? Because this method
checks if there is a pending job. If there is a pending job and its state is
ERROR, that means that the pending job failed due to a network failuire, or user
aborted the application. If we call Resume BITS try to connect again.
It will try to connect for 5 secs (NoProgressTimeout constant). If it couldn’t
do it, the job will stay in ERROR state. If not, it will transfer from the last
byte transferred.
The code in bold
letter need to be added
 
if (
jobState == BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED )
{
      
OnJobTransferred( task, copyJob );
       return true;
}
if (
jobState == BG_JOB_STATE.BG_JOB_STATE_ERROR || jobState ==
BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR ) {
      
copyJob.Resume();
}
 
Observations
  • This new code was
    tested in this scenarios: stopping the website; disabling the network card and
    aborting the application in the middle of the job, and it worked on all the
    scenarios. The job was resumed from the last byte transfered
  •  It’s important to
    attach to the PendingUpdatesDetected event of the
    ApplicationUpdaterManager. On the handler of this event call
    ResumePendingUpdates. This is important because this method
    deserializes the tasks that holds the BITS Job ID previously
    aborted.
  • It is not recommended
    to debug the WaitForDownload method due to concurrency and sync issues.
    Instead, tracing is recommended. A simple tracing could be implemented to
    troubleshoot, just by using the Logger.LogInformation method that will
    write to the Event Viewer.