dotnet / deployment-tools

This repo contains the code to build the .NET deployment tools and installers for all supported platforms, as well as the sources to .NET deployment tools.
MIT License
163 stars 50 forks source link

Improve update detection for .NET (Core) applications deployed with ClickOnce #27

Open NikolaMilosavljevic opened 3 years ago

NikolaMilosavljevic commented 3 years ago

.NET (Core) applications deployed with ClickOnce cannot use ApplicationDeployment class for on-demand update check.

Besides checking for new updates, this check can be used to ensure that the deployment is still available on the server and wasn't deleted. If application is doing silent updates, without this check, user won't be aware that application is not getting any updates.

Launcher could do the update check if application is configured to install new updates automatically. We need to find a way to communicate the result of this check to .NET (Core) application. We could potentially also include the result of any recent automatic update.

Rmurray0809 commented 3 years ago

Would there be any reason ClickOnce couldn't just drop a JSON file with information into the application directory when it is started? It seems like this would allow an easy way for the application find out information about the install (ie put the version thats on the server, the install URL etc). It could have extra information in it that would allow the developer to take action based on the information (exceptions?). This would also make it fairly extensible so if someone wanted to add information in the future they could and generally applications will just continue to work.

NikolaMilosavljevic commented 3 years ago

@Rmurray0809 yes, a similar approach is considered - we'll have more details on the design soon.

TimKras commented 3 years ago

Any updates about this?

NikolaMilosavljevic commented 3 years ago

@TimKras thank you for the interest in this feature. We don't have an estimate, yet, when it would be available as a preview.

cc @dleeapho

derskythe commented 3 years ago

For those people who want to use ClickOnce on .NET 5 and want silently update, I wrote a small wrapper that implements some of the ApplicationDeployment properties:

Hope this helps someone: https://github.com/derskythe/WpfSettings

greatoceansoftware commented 3 years ago

I definitely need the functionality of ApplicationDeployment. I can't seeing declaring victory of bringing ClickOnce to .NET 5/6 without it.

This is mainly because the limitation of only checking at application startup is annoying for most users. It's funny that they don't mind a splash screen with loading progress, but they mind this. Mainly because they want update checking AT THEIR CONVENIENCE. And I agree in the case of most of my applications.

Thanks for any consideration. Without it, it's back to commercial installers.

jonrmorgan99 commented 3 years ago

Totally agree - without in-app updating ClickOnce is neutered. MSIX is not a real world alternative at present. Under NetFX ClickOnce proved it's reliability which is presumably why it made the cut to .Net5/6.

So please re-open this issue and let's have a progress update. Thanks.

luronumen commented 3 years ago

Unable to port WinForms project from .NET Framework 4.8 to .NET 5.0 due to the following issue: CS0234 - The type or namespace name 'Deployment' does not exist in the namespace 'System' (are you missing an assembly reference?)

jonrmorgan99 commented 2 years ago

@derskythe

For those people who want to use ClickOnce on .NET 5 and want silently update, I wrote a small wrapper that implements some of the ApplicationDeployment properties

Thanks for posting this workaround for the missing ApplicationDeployment methods in Net5. You mention that the workaround features Silent Updates. However on my setup OpenURL(setuppath) in your Update code boots my browser and offers to download the application manifest manually. Any idea how I can get the app to update silently ?

Thanks.

alansingfield commented 2 years ago

If you just need an "Update Now" button in your app, you can shell out to this command and then exit.

rundll32 dfshim.dll,ShOpenVerbApplication http://yourupdateurl/yourapp.application
Mrxx99 commented 2 years ago

This is on the 6.0 milestone, so will this be fixed until next week?

DDD25583 commented 2 years ago

I just tried to migrate a net4.8 app to .NET 6 when I came across this issue. Being able to get the CurrentVersion is crucial in are error and bug-processing procedures. As the production environment contains a lot of computers, updating (close and restart) an app is done once in the 24 hours. So it is important that we know on which version of the app, an error is thrown.

simmotech commented 2 years ago

Based on ideas/code from @derskythe, @alansingfield, @e-master, I created a repro at https://github.com/simmotech/Net6ClickOnce which passes through all the info from args/ApplicationDeployment/ActivationArguments to the .NET 6 ClickOnce app. It also allows in-app detection of any later version and updating to that version on close.

Might be worth a look to use until an official fix is made. Grateful for any suggestions/further testing.

jonrmorgan99 commented 2 years ago

Great to see ClickOnce in Net6, but still no progress on restoring the in-app updating functions in Application.Deployment.

Is there any update on this issue ? Net 7 maybe ??

raffaeler commented 2 years ago

@NikolaMilosavljevic Do you have any news for this? We are still stuck since https://github.com/dotnet/deployment-tools/issues/9#issuecomment-726207037 This really prevents the migration of a large number of applications.

NikolaMilosavljevic commented 2 years ago

@NikolaMilosavljevic Do you have any news for this? We are still stuck since #9 (comment) This really prevents the migration of a large number of applications.

We are definitely tracking improvements in ClickOnce experience for .NET (Core) apps, for upcoming release. You can expect to see some designs published in the next several weeks. Improvements might be brought up in stages, to allow for a better design and experience, as well as more testing with early previews.

raffaeler commented 2 years ago

@NikolaMilosavljevic Thanks for the prompt answer.

I noticed that the new publishing wizard creates far more files than in the past. The applications file are copied in both the publish folder and the sub-folder that is versioned. Why does this differ from the past? I expected to see basically the same set of files, even because we host these files in a web application were there are both old and new ClickOnce apps.

NikolaMilosavljevic commented 2 years ago

@NikolaMilosavljevic Thanks for the prompt answer.

I noticed that the new publishing wizard creates far more files than in the past. The applications file are copied in both the publish folder and the sub-folder that is versioned. Why does this differ from the past? I expected to see basically the same set of files, even because we host these files in a web application were there are both old and new ClickOnce apps.

Adding @John-Hart and @sujitnayak for the publishing wizard question.

John-Hart commented 2 years ago

The new ClickOnce for .NET publish wizard is essentially built on top of the standard .NET Folder Publish, after it runs and copies the files to the output folder, ClickOnce publish creates the manifest, setup.exe, launcher.exe and publish.html and then it copies the application files into the Application Files folder. So that does mean there is an extra copy of the application files left in the output folder.

jonrmorgan99 commented 2 years ago

Thanks for the explanation John.

It is really tedious to have to weed out the extra copy of the application files each time you do a Net6 CO build.

Is there any possibility of getting ClickOnce in Net6 to delete these unneeded files ?

As has been pointed out the Netfx CO build format was nice and clean – just the Application files folder, manifest, setup and publish.

From: John Hart @.*** Sent: 23 February 2022 20:40 To: dotnet/deployment-tools Cc: jonrmorgan99; Comment Subject: Re: [dotnet/deployment-tools] Improve update detection for .NET (Core) applications deployed with ClickOnce (#27)

The new ClickOnce for .NET publish wizard is essentially built on top of the standard .NET Folder Publish, after it runs and copies the files to the output folder, ClickOnce publish creates the manifest, setup.exe, launcher.exe and publish.html and then it copies the application files into the Application Files folder. So that does mean there is an extra copy of the application files left in the output folder.

— Reply to this email directly, view it on GitHub https://github.com/dotnet/deployment-tools/issues/27#issuecomment-1049195880 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ASTASBL3XBVKPEU4DTQTEMDU4VA3XANCNFSM4QHNJGIQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub . You are receiving this because you commented. https://github.com/notifications/beacon/ASTASBN54Q6FY54YTZHWNC3U4VA3XA5CNFSM4QHNJGI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOH2EXK2A.gif Message ID: @.***>

John-Hart commented 2 years ago

@jonrmorgan99 we do have a feature suggestion to remove the extra files, feel free to vote on https://developercommunity.visualstudio.com/t/Clickonce-for-NET-Core-issues/1500772 if you would like to see that feature.

In the meantime you might be able to try using the powershell remove-item command like this:

remove-item * -exclude *.application,launcher.exe,setup.exe,publish.html,'Application Files'
berets76 commented 2 years ago

Is it so difficult to give a definitive answer about System.Deployment in NET >= 6 ? Please, simply tell us if we will get back IsNetworkDeployed and other properties and functions or not.

We don't need exotic solutions or dangerous shell-based workarounds, please just say yes or no, so we can evaluate alternatives with our customers.

Thanks

NikolaMilosavljevic commented 2 years ago

Is it so difficult to give a definitive answer about System.Deployment in NET >= 6 ? Please, simply tell us if we will get back IsNetworkDeployed and other properties and functions or not.

We don't need exotic solutions or dangerous shell-based workarounds, please just say yes or no, so we can evaluate alternatives with our customers.

Thanks

We plan to add support for IsNetworkDeployed and other properties that were previously exposed with https://docs.microsoft.com/en-us/dotnet/api/system.deployment.application.applicationdeployment?view=netframework-4.8

Properties will be available to .NET app as process environment variables. A simple class could be implemented, by the app developer, to abstract those variables and make their usage easier and very similar to old ApplicationDeployment class. We will provide the sample usage as part of the PR for this work, and in documentation.

The work is happening during 7.0 dotnet-mage development.

jonrmorgan99 commented 2 years ago

@NikolaMilosavljevic Thanks for the update.

What's needed for users hoping to port NetFx ClickOnce apps to Net6/7 is a complete rebuild of the ApplicationDeployment class for Net6/7, not just a few properties.

We need to be able to replicate the code example in

https://docs.microsoft.com/en-us/dotnet/api/system.deployment.application.applicationdeployment?view=netframework-4.8

which is the de-facto standard for implementing in-app updating with ClickOnce.

This means exposing events such as CheckforUpdateCompleted, CheckForUpdateProgressChanged and UpdateCompleted as well as methods such as CheckForUpdate/CheckForUpdateAsync and Update/UpdateAsync.

Please explain how process environment variables could be used to replace this essential functionality. As @berets76 commented, shell-based workarounds raise security risks.

ApplicationDeployment is an elegant, simple to use, robust solution to in-app updating with ClickOnce.

Why fix it if it ain't broke ?

Thanks

NikolaMilosavljevic commented 2 years ago

@jonrmorgan99, in-app update is not something that can simply be enabled, for ClickOnce-deployed .NET apps. There is no ClickOnce runtime in .NET (Core), with which the app can interact and initiate in-app update.

Launcher (built as .NET FX app) was added as a necessary entry point that 'hooks-up' to ClickOnce runtime. That model provides automatic updates, update check before launch, and, with upcoming addition, exposes various app properties, like URL parameters.

I understand that there is convenience, and perhaps a need for some types of applications, in checking for updates and performing update step while application is running. The app would still need to be restarted in the end. New properties will provide easy to consume insight into application Uri. This will enable a deterministic app restart using some of dfshim exports, i.e. LaunchApplication or ShOpenVerbApplication. App restart would let it download the pending update before launch.

The only missing piece is how to determine if there is a pending update available at deployment location. While there are no ready to use APIs at the moment, your application could do this check in a more direct way by determining the version that is available on the server. Certainly not ideal, but an alternative that would work.

UFuz commented 2 years ago

Might be worth a look to use until an official fix is made. Grateful for any suggestions/further testing.

@simmotech I just tried your code. So I assume, I need to copy "launcher.exe" over the one generated by VST? Doing this, when installing from the deploy location, I run into "Reference in the manifest does not match the identity of the downloaded assembly Launcher.exe." error. I am using the built in signing process. Can you or someone reading this, provide me steps how to re-sign this in an automated way? Unfortunately I am not experienced in doing this manually.

alansingfield commented 2 years ago

@UFuz - you've probably copied the Launcher.exe AFTER the manifest files have been generated. The manifest contains a SHA256 hash of the executable, so if you amend the Launcher.exe the hash won't match.

OR - you might have chosen the wrong CPU type for your Launcher; check whether x86, x64 or "Any CPU".

There is also some other weirdness in that the behaviour of "dotnet mage -New Application" changes significantly depending on if there is a file called Launcher.exe alongside your main exe or not. If not, it uses the .NET 4.8 protocol where every file is SHA256 hashed. If Launcher.exe exists, I think it only hashes Launcher.exe itself. Don't quote me on that, it's a while since I did this...

Have a look at these: https://github.com/dotnet/deployment-tools/issues/149 https://github.com/alansingfield/ClickOncePowershell

khaheldev commented 2 years ago

Hello! Will this be available on .NET 7? Thanks!

NikolaMilosavljevic commented 2 years ago

The work to expose properties of ApplicationDeployment class to .NET app is happening right now. It will be available soon, in one of our Previews, during .NET 7 development. Please note that dotnet-mage ships as .NET Global tool and not as part of .NET release (i.e. 7).

UFuz commented 2 years ago

If you just need an "Update Now" button in your app, you can shell out to this command and then exit.

rundll32 dfshim.dll,ShOpenVerbApplication http://yourupdateurl/yourapp.application

@alansingfield : With original .Net4.8 update mechanism, I used to run ApplicationDeployment updateCheck = ApplicationDeployment.CurrentDeployment; updateCheck.Update(); show a success messagebox; Application.Restart();

with the "dfshim.dll" approach I have 3 issues: 1) it returns immediately, not waiting for the update to complete 2) application.restart will relaunch the old version, instead of the new 3) restarting by desktop icon does not maintain the application settings, so app starts with defaults

Is there a way to improve this, especially point 3?

heku commented 1 year ago

except the issue discussed above, I have another question, anybody know why a .net 6 WPF application with "online" mode only, cannot update itself when a new version published?(the application is not signed, but I didn't see any doc says update detect needs sign)

NikolaMilosavljevic commented 1 year ago

except the issue discussed above, I have another question, anybody know why a .net 6 WPF application with "online" mode only, cannot update itself when a new version published?(the application is not signed, but I didn't see any doc says update detect needs sign)

@heku was the application built using dotnet-mage or ClickOnce publishing in Visual Studio?

cc @sujitnayak @John-Hart

sujitnayak commented 1 year ago

@NikolaMilosavljevic The VS ClickOnce behavior in .NET 6.0 apps is consistent with .NET 4.X. Update is not enabled if app is Online only.

heku commented 1 year ago

@sujitnayak visual studio, it is totally different as my expectation, I thought Online mode means always “latest”, if so, what the purpose of Online mode?

John-Hart commented 1 year ago

@heku this might help: https://learn.microsoft.com/en-us/visualstudio/deployment/how-to-specify-the-clickonce-offline-or-online-install-mode?view=vs-2022

heku commented 1 year ago

@John-Hart Thx, I saw the doc before, it only says the difference of online/offline is online needs access to publish location, never mentions any difference about update behavior

sujitnayak commented 1 year ago

Behavior of auto-update not being available in online-only mode is not new to .NET 6.0 apps. .NET 4.X apps have had the same behavior as you can see in the screenshot attached:

image

Auto-update is for apps that are installed locally on the machine (visible in Add Remove Programs and Start menu) which happens only when offline mode is also available for the app.

heku commented 1 year ago

@sujitnayak ok, the "updates" button is disabled for Online mode, I thought it means Online mode app is always up to date, that what I really misunderstand. since it has same behavior as .NET Framework, I have no question any more, thank you.

LeDahu22 commented 1 year ago

The work to expose properties of ApplicationDeployment class to .NET app is happening right now. It will be available soon, in one of our Previews, during .NET 7 development. Please note that dotnet-mage ships as .NET Global tool and not as part of .NET release (i.e. 7).

Any update on this ? .Net 7 was released yesterday yet ApplicationDeployment class is still unrecognized. Do we need to install something else in order to get this working ?

NikolaMilosavljevic commented 1 year ago

ClickOnce support for .NET ships separately from main .NET (i.e. .NET 7). It ships as a global tool. We will be releasing version 7.0.0 of dotnet-mage in the next few days.

This feature is available in our preview release: https://www.nuget.org/packages/Microsoft.DotNet.Mage/7.0.0-preview.2.22317.2. For all previews you'd need to specify explicit version number, to install it, following the steps for the tool installation from the doc page: https://github.com/dotnet/deployment-tools/tree/main/Documentation/dotnet-mage

Please note that this feature is already available in Visual Studio 2022 build 17.3 or later.

Here's the relevant PR with more details about this feature and some examples: https://github.com/dotnet/deployment-tools/pull/208

tejs-code commented 1 year ago

@NikolaMilosavljevic Is there an alternate to UpdateAsync, a way to install the update in the backgroun? I understand the app has to be restarted anyway, but it provides a way to download and process update in the background without paying a cost on open and showing a dialog to the user whether to install the update or not.

TimKras commented 1 year ago

@NikolaMilosavljevic How should this feature used in an application. Do we need to read the Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed") manually, or will there be a wrapper? Or should we use this class in our application: https://github.com/dotnet/deployment-tools/blob/dfb0a98c68da39fc9cd1d82e200a19badf4e7112/Documentation/dotnet-mage/ApplicationDeployment.cs

NikolaMilosavljevic commented 1 year ago

@NikolaMilosavljevic How should this feature used in an application. Do we need to read the Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed") manually, or will there be a wrapper? Or should we use this class in our application: https://github.com/dotnet/deployment-tools/blob/dfb0a98c68da39fc9cd1d82e200a19badf4e7112/Documentation/dotnet-mage/ApplicationDeployment.cs

Yes, at the moment, those would be the only 2 solutions. You could use that sample wrapper class or create a new own. Reading environment variables would also work, if you only need to use a few.

NikolaMilosavljevic commented 1 year ago

@NikolaMilosavljevic Is there an alternate to UpdateAsync, a way to install the update in the backgroun? I understand the app has to be restarted anyway, but it provides a way to download and process update in the background without paying a cost on open and showing a dialog to the user whether to install the update or not.

There is no alternative today, for silent update, which was provided by UpdateAsync in the past (for .NET FX apps). That experience requires running update in the app context, which isn't possible today as System.Deployment library is not available in .NET.

We understand that this is an important scenario for some applications and will be looking into ways to close this gap in experience.

luronumen commented 1 year ago

Hi @NikolaMilosavljevic

I noticed that the ApplicationDeployment.cs class still missing the 2 methods that are available on ClickOnce for .NET 4.8 Framework:

Is there any plan to implement them or any alternative methods to them on .NET 7.0?

Thanks in advanced, Luciano

NikolaMilosavljevic commented 1 year ago

Hi @NikolaMilosavljevic

I noticed that the ApplicationDeployment.cs class still missing the 2 methods that are available on ClickOnce for .NET 4.8 Framework:

  • CheckForDetailedUpdate()
  • Update()

Is there any plan to implement them or any alternative methods to them on .NET 7.0?

Thanks in advanced, Luciano

That is correct. The sample class adds support for obtaining properties and does not have any methods related to updating the app. We understand that this is an important scenario for some applications and will be looking into ways to close this gap in experience.

luronumen commented 1 year ago

That is correct. The sample class adds support for obtaining properties and does not have any methods related to updating the app. We understand that this is an important scenario for some applications and will be looking into ways to close this gap in experience.

Thank you very much for your prompt reply @NikolaMilosavljevic ! Are these gaps planned to be resolved in .NET 7.0 or will they only be available in .NET 8.0?

Thanks again!

NikolaMilosavljevic commented 1 year ago

Those features are not planned for 7.0, which GA'd last week. dotnet-mage, which will GA in a day or two, always support building deployments for older .NET versions, unless that is not feasible. For instance, new features that we add in dotnet-mage version 8 would support .NET 8.0, and all previous .NET releases.

jonrmorgan99 commented 1 year ago

Hi @NikolaMilosavljevic

Just following up @luronumen and your response:

I noticed that the [ApplicationDeployment.cs](https://github.com/dotnet/deployment-tools/blob/dfb0a98c68da39fc9cd1d82e200a19badf4e7112/Documentation/dotnet-mage/ApplicationDeployment.cs) class still missing the 2 methods that are available on ClickOnce for .NET 4.8 Framework:

    CheckForDetailedUpdate()
    Update()

Is there any plan to implement them or any alternative methods to them on .NET 7.0?

Thanks in advanced, Luciano

That is correct. The sample class adds support for obtaining properties and does not have any methods related to updating the app. We understand that this is an important scenario for some applications and will be looking into ways to close this gap in experience.

Has there been any progress in restoring methods for updating ClickOnce apps ? Is there a timeline to include them in .NET 8.0 ? Is there anything the user community can do to help ?

Thanks for continuing to develop ClickOnce !

mike7ang1rdz commented 1 year ago

ClickOnce support for .NET ships separately from main .NET (i.e. .NET 7). It ships as a global tool. We will be releasing version 7.0.0 of dotnet-mage in the next few days.

This feature is available in our preview release: https://www.nuget.org/packages/Microsoft.DotNet.Mage/7.0.0-preview.2.22317.2. For all previews you'd need to specify explicit version number, to install it, following the steps for the tool installation from the doc page: https://github.com/dotnet/deployment-tools/tree/main/Documentation/dotnet-mage

Please note that this feature is already available in Visual Studio 2022 build 17.3 or later.

Here's the relevant PR with more details about this feature and some examples: #208

are you guys not releasing a non preview version to a LTS NET version?. We are currently releasing to NET 6 and due to short-term support not releasing to NET 7.

you should also target to NET 6 because it is LTS.