Best way to deal with a restarting app after update

Jul 27, 2014 at 1:02 PM
Edited Jul 27, 2014 at 1:14 PM
Hi Bladewise,

First off, a massive thank you for developing and releasing this package - it is incredibly useful and a very clean solution!

I just have a quick question regarding best practices when restarting an app, and thought it best to run my thoughts by you.

My (Caliburn Micro) application uses an external framework to auto-update... Part of the auto-update process causes the old app and new app to potentially be run simultaneously for a short time.

Sometimes (about half the time) the new version of the app registers successfully as the "first instance" but the other times, the new-version app thinks it is the second instance.

I definitely want the new version to think of itself as the first instance, and was trying to work out the best way for it to do this. My better ideas were the following two:

1) Before the app runs the update routine, it 'deregisters' as the first instance (ie releases the MuTeX, destroys the service host etc)
2) We can use separate application ids/GUIDs based on build number.

Ideally I think it would be nice to keep the same GUID between different builds of the same app, which I think makes (1) the best choice? But I was wondering how I should do that with your package. Reading through, I can see TryDisposeSynchronizationObjects() seems to be what I want. It is obviously private, but called through from Dispose()...

So I could add something like this in my App.xaml.cs :
    public partial class App
        public void Reliniquish_position_as_first_instance()
And then, after I download the new update, but before I tell it to update, I could run Reliniquish_position_as_first_instance(). Do you think this is the correct way to achieve this? (in particular, is it correct to call Dispose in this way?)

Thank you in advance for reading through all this, and for any help/advice you may be able to offer!
Jul 27, 2014 at 3:03 PM
Changing the Guid can be a nice idea, still I would avoid it, otherwise whatever old and new app could potentially run at the same time.
Switching between first and next instance, should be feasible with few to none effort, since synchronization is dealt with just two methods: InitializeInstance and TryDisposeSynchrionizationObjects. Such methods are called during the startup/exit phases, but do not invoke code that is actually part of the Application lifecycle.
The only problem is that the current version of this library do not expose such methods to inheritors, since they are privare.
All in all, I think that a modification to the code-base is necessary, to deal with more complex scenarios where the first/master instance can change at runitme.

I'll try to make necessary modifications, update the package and provide a sample.
Jul 27, 2014 at 6:10 PM
Okay, great, I agree with you fully :).

If you could do that, that would be absolutely perfect! Thanks for putting your time into it, it's very kind of you.

This package is so useful, I'm really surprised it hasn't got more attention! I'll definitely try to promote it a bit more if I get the chance!

Jul 28, 2014 at 10:09 PM
I have just pushed a new release (on NuGet too), with some extra changes (see the changeset notes) that can be not compatible with the previous version.
Most notably, the IsFirstInstance property (and parameter in OnStartup) is nullable, since once synchronziation objects are relinquished, the application is no more 'part' of the instance aware context (thus, being first or next instance, does not make sense, in my opinion).
I've renamed the methods above to InitializeSynchronizationObjects and RelinquishSynchronizationObjects, and you should be able to use them to achieve your goal with few effort.
I've updated the sample to show how an application can relinquish her 'first' status.

Hope these changes are useful, if you have more questions, or encounter a bug, I will gladly try to help.
Jul 29, 2014 at 12:17 AM
Wow, that's fantastic, thanks for all your help!

Once again, that seems like a really clean solution (particularly the nullable bool) - will try it out tomorrow! :)