We're going to look into this either tonight or sometime later tomorrow afternoon. I'll get back to you.
Hi.
I'm having huge problems with AutomaticUpdaterBackend. I use it for updating my windows services. I tried all four modes (Automatic, CheckAndDownload, OnlyCheck and DoNothing), and only Automatic works 100%. The other three all go stuck before the update process has completed.
My system: - Windows XP Professional SP3 - .NET 4.0 (yes, I use the 4.0 version of AutomaticUpdater.dll) - wyBuild 2.6.14.0 (the most recent version)
Here are my observations:
Automatic mode (works):==============1) I call ForceCheckForUpdate()2) I get the BeforeCheck event 3) I get the ProgressChanged event (100)4) I get the BeforeDownloading event5) I get a row of ProgressChanged events (7% to 100%)6) I get a BeforeExtracting event7) I get a row of ProgressChanged events(0% to 83%)8) I get a ReadyToBeInstalledEvent9) I call InstallNow()10) The service rastarts in its new version. Everything OK.
Note: If one of the original files to update are missing, I get an UpdateStepMismatch event an an extra row of ProgressChanged events. I assume this is when the system takes the "all.to.x.x.x.x" update file into use. Butthe system still works.
CheckAndDownload mode (with clean files to be updated - works):===========================================
1) I call ForceCheckForUpdate()2) I get the BeforeChecking event3) I get the ProgressChanged (100) event4) I get the BeforeDownloading event5) I get a row of ProgressChanged events (6% to 100%)6) I get the ReadyToBeInstalled event - UpdateStepOn shows: UpdateDownloaded 7) I call InstallNow()8) I get the BeforeExtracting event9) I get a row of ProgressChanged events (0%-83%)10) I get a new ReadyToBeInstalled event - UpdateStepOn shows: UpdateReadyToInstall11) I call InstallNow() anew12) The service restarts in its new version. Everything OK.
CheckAndDownload mode with a missing file - DOES NOT WORK:=========================================
1) I call ForceCheckForUpdate()2) I get the BeforeChecking event3) I get the ProgressChanged (100) event4) I get the BeforeDownloading event5) I get a row of ProgressChanged events (6% to 100%)6) I get a ReadyToBeInstalled event - UpdateStepOn shows: UpdateDownloaded7) I call InstallNow()8) I get a BeforeExtracting event9) I get a row of ProcessChanged events (8% to 83%)10) I get an UpdateStepMismatch event11) I get a longer row of ProgressChanged events (3% to 100%)12) I get a new BeforeExtracting event13) I get a row of ProgressChanged events (0 to 85%)14) I get a ReadyToBeInstalled event - UpdateStepOn shows: UpdateReadyToInstall15) I call InstallNow() anew16) NOTHING HAPPENS.... SYSTEM HAS GONE STUCK! UpdateStepOn keeps on showing UpdateReadyToInstall...
OnlyCheck mode - DOES NOT WORK (not even with clean original files)=================================================1) I call ForceCheckForUpdate()2) I get the BeforeChecking event3) I get the ProgressChanged (100) event4) I get the UpdateAvailable event5) I call InstallNow()6) I get a BeforeDownloading event7) I get a row of ProgressChanged events (6% to 100%)8) I get a BeforeExtracting event9) I get a row of ProgressChanged events (0% to 83%)10) I get a ReadyToBeInstalled event - UpdateStepOn shows: UpdateReadyToInstall11) I call InstallNow() anew12) NOTHING HAPPENS.... SYSTEM HAS GONE STUCK! UpdateStepOn keeps on showing UpdateReadyToInstall...
DoNothing mode - does NOT work (not even with clean original files)=================================================1) I call ForceCheckForUpdate()2) I get the BeforeChecking event3) I get the ProgressChanged (100) event3) I get the UpdateAvailable event4) I call InstallNow()5) I get a BeforeDownloading event6) I get a row of ProgressChanged events (6% to 100%)7) I get a BeforeExtracting event8) I get a row of ProgressChanged events (0% to 83%)9) I get a ReadyToBeInstalled event - UpdateStepOn shows: UpdateReadyToInstall10) I call InstallNow() anew11) NOTHING HAPPENS.... SYSTEM HAS GONE STUCK! UpdateStepOn keeps on showing UpdateReadyToInstall...
I would like to use the DoNothing mode, that fires the UpdateAvailable event before downloading, because this way I can the offer the operator not to update this time but simply await the next update to come up instead. All it takes to do this is to call ForceCheckForUpdate( true ) repeatedly after the UpdateAvailable event (instead of InstallNow()) until another update shows up (another UpdateAvailable event will then fire).
Please investigate why CheckOnly and DoNothing modes don't work at all, and why CheckAndDownload mode does not work when original files have been messed with.
- Martin.
We're going to look into this either tonight or sometime later tomorrow afternoon. I'll get back to you.
I discovered that I forgot to call AppLoaded() after my call to Initialize(). However, I added the call and ran the program again (using DoNoting mode) but with the same results.
It's a bit difficult to replicate each try because of wyUpdate's caching mechanism - most often I have to run the test twice in order to get the downloading and file extraction to happen. If updates are cached from an earlier non-completed update process, updating usually happens almost instantly and without problems (=getting the UpdateReadyToBeInstalled event very quickly, and InstallNow() then completes the job).
-Martin.
Well, forgetting AppLoaded() will cause a lot of problems (because it sets up the AutomaticUpdater state and calls the correct events). But I'll check into the DoNothing problem.
We can't reproduce this here. In all cases the updating works fine. Can you send me a simple service that can reproduce this behavior? Send it to wyatt@wyday.com
11) NOTHING HAPPENS.... SYSTEM HAS GONE STUCK! UpdateStepOn keeps on showing UpdateReadyToInstall...
Does your service stop? Is wyUpdate running in the task manager? Or does it close?
Good morning Wyatt, and thank you very much for your efforts so far.
I will send you a small service that does nothing, and that reproduces the behaviour. An to your questions:
No, the service doesn't stop.
I tried the scenario again this morning, this time the sytem went stuck in state "ExtractingUpdate". Last event recevied was "BeforeExtracting". wyUpdate.exe keeps running in TaskManager (with 00% CPU load).
Hey Martin,
There's quite a bit of code to work through here -- it'll take me a while to find the root cause of the problem. My instincts tell me (and from what you're saying on our forum) it looks like you're not handling an event from the AutomaticUpdater correctly.
Here's what I mean. From what you say, when the AU UpdateType is set to "Automatic" then everything works fine. The "Automatic" UpdateType is only different from the other UpdateTypes in that the AU handles taking the next step automatically (instead of forcing you to call the correct functions).
That being said there might be a bug in the AutomaticUpdater. I'll only know once I work through your code. This could take several days. If you want a quicker resolution to this problem here's how you can handle it:
Get the AutomaticUpdater source code (http://wyday.com/wybuild/help/automatic-updates/ ). Add your project to the VS Solution, and step through your code in a debugger and see why it works with UpdateType = Automatic, and not the other UpdateTypes.
That's what I'll be doing a little bit later.
Hi Wyatt.
I'm sorry for stealing so much of your time with my problem. You mention that I probably do not handle an event from AU correctly. Could you tell me in a few words what correct handling should be?
I my code I have attached event handlers to every single AU event I could find, but - apart from UpdateAvailable and UpdateReadyToInstall - the event handlers only output debug messages. The two mentioned event handlers basically only cause InstallNow() to be called in order to get the update process completed. Shouldn't it suffice just to call InstallNow() in response the the two events?
However, in my code InstallNow() is called from a dfferent thread from the one calling ForceCheckForUpdate() and from the one fireing the events - is that a problem? I'm at home now, but tomorrow I will cut down my code even more and send it to you anew, so you won't have more code than necessary to go through. Wouldn't that be nice?
- Martin
However, in my code InstallNow() is called from a dfferent thread from the one calling ForceCheckForUpdate() and from the one fireing the events - is that a problem?
This sounds like it might be the problem. We're changing how services are stopped in AU 2.6.15. Right now, we call Environment.Exit(0); to kill the service. In 2.6.15 we're going to call ServiceBase.Stop(). This should fix some of the threading issues involved with services.
In the meantime try calling InstallNow() with the main service thread.
Hi Wyatt.
I have done a lot of debuggung with your source code and I have now found out what goes wrong. I have also found a way to solve it.
The problem lies in the AutomaticUpdater.dll (.NET4 version).
The AutomaticUpdaterBackend makes use of a BackgroundWorker object to get update steps done in the background in a separate thread.
When my test service goes stuck while updating it is because the BackgroundWorker object at a certain step in the update process keeps holding its IsBusy property true even though the code in the bw_DoWork event handler has completed. While debugging I also found that that the bw_RunWorkerCompleted event handler was never called in that case.
That puzzled me very much because I could follow the completion of the code in the bw_DoWork event handler, and according to Microsoft's documentation to the BackgroundWorker class this should indeed cause the RunWorkerCompleted event to be fired (and the IsBusy property to go false). But it didn't.
Then I did quite a bit of googling and finally I came across this thread:
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/a4c919a6-b6cc-4a4f-bda7-c7585a57b4eb(title: "Background Worker not firing RunWorkerCompleted event" )
After some experimenting I was able to solve the problem by modifiying the UpdateHelper class this way:
* Instead of reusing the same BackgroundWorker instance over and over I now create a new instance for each job to be run (and remember to properly get rid of the old one).* Prior to each creation of a new BackgroundWorker instance (and setting up event handlers) I call System.Windows.Forms.Application.DoEvents(); (inspired by my google search)* Right after creation I remember to set bw.WorkerReportsProgress=true; and bw.WorkerSupportsCancellation=true;* In the bw_DoWork event handler i also added a call to System.Windows.Forms.Application.DoEvents() as the very last statement.
I encapsulated the recreaton of BackgrondWorker instances into the follwing method:
private void RecreateBackgroundWorker() { if (bw != null) { bw.DoWork -= bw_DoWork; bw.RunWorkerCompleted -= bw_RunWorkerCompleted; bw.Dispose(); bw = null; }
if (bw == null) { System.Windows.Forms.Application.DoEvents(); bw = new BackgroundWorker(); bw.DoWork += bw_DoWork; bw.RunWorkerCompleted += bw_RunWorkerCompleted; bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; } }
which I call from within the SendAsync(...) method - I'm sure you get the picture.
Result: NOW EVERYTHING WORKS!
New questions: - Is there a risk that my calls to System.Windows.Forms.Application.DoEvents() have unwanted side effects?- Would you consider implementing this change in the next version of AutomaticUpdater?
-Martin
Thanks Martin. Can you bundle up your modified AutomaticUpdater source code and send them to me -- wyatt@wyday.com?
Also, why are you setting "WorkerReportsProgress " and "WorkerSupportsCancellation"? We don't use the CancelAsync() method or the progress reporting for the BW.
Hi again, Wyatt.
I have done some more debugging and it turns out that:
* WorkerReportsProgress and WorkerSupportsCancellation properties do not need to be set (as you said).* There is no need to use a new BackgroundWorker instance for each job* All there is needed is calling System.Windows.Forms.Application.DoEvents() in "certain places" to ensure that the bw_RunWorkerCompleted eventhandler is eventually called every time!
My modified AutomaticUpdater.dll now only differs from the original one by having three DoEvents() calls added in UpdateHelper.cs - I will send the updated version of this file to you in an email.
Now only two tings really nag me:* I really don't understand WHY this change resolves the problem - but it does! (can you explain it to me, you clever guys? * I cannot judge if the change i made has unwanted side effects when using the AutomaticUpdater on a form. I will leave it up to you to answer that question. too.
Please let me know about your findings and what you think of it!
Regards, Martin.
Thank you for the updated AutomaticUpdater.dll I received by email. I have now tested it in my service and found that it works well. Thanks a lot.
- Martin.
Great, I'm glad the fixed AutomaticUpdater is working. We're still looking into the exact cause of the problems.
wyBuild 2.6.16 is now out -- this bug is fixed.
fyi, this is a terrible solution. here is why.
this causes a very problematic state for windows event-driven apps, and i suspect that this "solution" only works for the OP because it's restarting the event-loop after it was crashed.
The reason this is a very bad solution is as follows:calling Application.DoEvents(); INVOKES THE WINDOWS EVENTS.
meaning that if you check for updates on your main thread, and RecreateBAckgroundWorker() gets called (which will happen) then you end up with a event-loop inside of your previous event-loop (and the parent event loop having not finished)
so if your app has an event loop, beware!
The reason i found this is because I use locks, and having the recursive invocation of my main app's loop caused a deadlock to occur.
We'll look into a better solution to this problem. In the meantime you can use wyUpdate as a standalone updater.
fyi i just commented the offending line out and everything seems fine so far, however I have not done usability testing yet.
also fyi, i found this because i modified my app to recreate the AutomaticUpdaterBackend object every time i check for updates.
Why do I do that? Because I found another bug, where if writing the update to disk timesout, the updater backend's state is corrupted and causes the updater to not update.
and FYI i saw this when the user's computer goes to sleep while downloading updates. i became aware of this because i assert when the AutomaticUpdaterBackend .DownloadingFailed event triggers, which said some stuff about operation timeout writing to some file under User/wc. (Sorry i didn't write down the exact message)
restarting the app caused the update to work again, so I am guessing it's the AutomaticUpdateBackend that has a bug and not the wyUpdate.exe (thus I am now recreating the AutomaticUpdateBackend when checking)
Download the AutomaticUpdater source code. We have numerous examples in there.
My current environment:Windows 10AutomaticUpdater version: 2.6.18.4wyBuild version: 2.6.18.4Usage: Silent updates using a windows service and Automatic Updater BackendIssue: wyUpdateCommandline parameter of Automatic Updater Backend is not passing urlargs to my server on sub-sequent update checkings
Code base:auBackend = new AutomaticUpdaterBackend{ GUID = "95CD3430-3C1D-465D-B65D-8FC67A9E35B7",
// With UpdateType set to Automatic, you're still in // charge of checking for updates, but the // AutomaticUpdaterBackend continues with the // downloading and extracting automatically. UpdateType = UpdateType.Automatic,
// We set the service name that will be used by wyUpdate // to restart this service on update success or failure. ServiceName = "My Product Name", wyUpdateCommandline = "-urlargs:\"" + ProductName.GetInstallationId() + "\""};
auBackend.UpToDate += auBackend_UpToDate;auBackend.UpdateAvailable += auBackend_UpdateAvailable;auBackend.BeforeChecking += auBackend_BeforeChecking;auBackend.BeforeDownloading += auBackend_BeforeDownloading;
//TODO: use the failed events for logging & error reporting:// CheckingFailed, DownloadingFailed, ExtractingFailed, UpdateFailedauBackend.CheckingFailed += auBackend_CheckingFailed;auBackend.DownloadingFailed += auBackend_DownloadingFailed;auBackend.ExtractingFailed += auBackend_ExtractingFailed;auBackend.UpdateFailed += auBackend_UpdateFailed;
auBackend.ReadyToBeInstalled += auBackend_ReadyToBeInstalled;auBackend.UpdateSuccessful += auBackend_UpdateSuccessful;
auBackend.Initialize();auBackend.AppLoaded();RunEveryDay();
Logging:On first time Windows Service restarts :16-Jun-17 11:17:17 AM - New Version Ready To Be Installed.16-Jun-17 11:17:17 AM - User settings Backed up successfully16-Jun-17 11:17:18 AM - Automatic Updater started16-Jun-17 11:17:18 AM - New Version successfully updated. New Version: 1.216-Jun-17 11:17:18 AM - User settings Restored successfully16-Jun-17 11:17:18 AM - Service starting 16-Jun-17 11:17:38 AM - Automatic Updater time changed. 16-Jun-17 11:17:38 AM - File watchers restarting 16-Jun-17 11:17:38 AM - Automatic Updater started16-Jun-17 11:17:38 AM - File watchers started. 16-Jun-17 11:17:40 AM - Your ICD is up-to-date16-Jun-17 11:19:06 AM - Automatic Updater time changed. 16-Jun-17 11:19:06 AM - File watchers restarting 16-Jun-17 11:19:06 AM - Automatic Updater started 16-Jun-17 11:19:06 AM - File watchers started. 16-Jun-17 11:19:31 AM - New Version Downloading Failed. Reason: Error trying to save file: Error downloading "http://Myserver/Updates/DownloadUpdate?update=MyProduct-3.1.2.to.1.3.wyu&installationId=": The remote server returned an error: (403) Forbidden.
On the server side, I do have some logic to validate installationId for allowed users.The problem seems to be with AutomaticUpdaterBackend file. It sends the wyUpdateCommandline urlargs when making only the first request to server for updated version. As AutomaticUpdater passes installationId for first time.On each sub-sequent update check request it keeps missing to send the installationId to wyUpdate.exe app when it being called.I also implemented all the event handlers in my code mentioned above.
static void auBackend_BeforeChecking(object sender, BeforeArgs e){ Log.LogInformation("Before checking event raised", LogEventIDs.ServiceStart, Log.GeneralCategory); Log.LogInformation("auBackend wyUpdateCommandline: " + auBackend.wyUpdateCommandline, LogEventIDs.ServiceStart, Log.GeneralCategory);}
static void auBackend_BeforeDownloading(object sender, BeforeArgs e){ Log.LogInformation("Before downloading event raised", LogEventIDs.ServiceStart, Log.GeneralCategory); Log.LogInformation("auBackend wyUpdateCommandline: " + auBackend.wyUpdateCommandline, LogEventIDs.ServiceStart, Log.GeneralCategory);}
But neither of one event are being raised from above two at all before it tries to check for updater or download.According to AutomaticUpdaterBackend API:wyUpdateCommandline: Gets or sets the arguments to pass to wyUpdate when it is started to check for updates.But my server is not receiving InstallationId and I get an error as shown above with installation= as empty so download fails.
You've got a lot of code there, but the error message burried in the middle of everything is telling you exactly what is failing: New Version Downloading Failed. Reason: Error trying to save file: Error downloading "http://Myserver/Updates/DownloadUpdate?update=MyProduct-3.1.2.to.1.3.wyu&installationId=": The remote server returned an error: (403) Forbidden.
First of all thank you for your prompt response.I understand why it is failing because the installationId I am supposed to pass as urlargs when calling for an update is empty as you can see it in that error. So the server works as it is supposed to. The issue is when assigning urlargs in line: wyUpdateCommandline = "-urlargs:\"" + ProductName.GetInstallationId() + "\""My question is: Why does the AutomaticUpdaterBackend is not passing it along when making an update request to my server. Because if I enter the same address in a web browser with the correct installationId I am receiving an update.wyu file successfully.At the same time you can see that on the first update attempt it worked just fine with no issues and Automatic Updater Backend passed the InstallationId correctly and the product was updated. successfully to version 1.216-Jun-17 11:17:18 AM - Automatic Updater started16-Jun-17 11:17:18 AM - New Version successfully updated. New Version: 1.216-Jun-17 11:17:18 AM - User settings Restored successfully
I am not sure why but installing the AutomaticUpdater using Nuget package manager solved all the issues I was having. I thought it might be helpful for someone having same issues.
Now it is also raising the events as below:2017-06-19 11:54:00 AM - Before checking event raised2017-06-19 11:54:00 AM - auBackend wyUpdateCommandline: -urlargs:"1856A76A-92DC-452A-8ACC-B6C57214891F"2017-06-19 11:54:01 AM - Before downloading event raised2017-06-19 11:54:01 AM - auBackend wyUpdateCommandline: -urlargs:"1856A76A-92DC-452A-8ACC-B6C57214891F"2017-06-19 11:54:01 AM - New Version Ready To Be Installed.