ユーザーがClickOnceネットワークにデプロイされたアプリケーションの以前のバージョンに戻ることを許可する方法はありますか?
ドキュメントとAPIを調べましたが、方法がないようです。更新するかどうかを選択的に選択できますが、一度更新すると、元に戻す方法はないようです。
ユーザーがClickOnceネットワークにデプロイされたアプリケーションの以前のバージョンに戻ることを許可する方法はありますか?
ドキュメントとAPIを調べましたが、方法がないようです。更新するかどうかを選択的に選択できますが、一度更新すると、元に戻す方法はないようです。
サーバー マニフェスト ファイルを変更することで、サーバー側で古いバージョンに戻すことができます。クライアントがアプリケーションを再起動すると、サーバーが言う「現在の」バージョンとは異なるバージョンがあることがわかり、新しいバージョンがダウンロードされます。通常、このサーバー マニフェスト ファイルは常に最新バージョンを指していますが、必ずしもそうである必要はありません。
変更方法は次のとおりです (Visual Studio 2008 を使用して公開しました。他のバージョンでは、公開フォルダー構造が異なる場合があります)。
publish.htm と同じフォルダに、.xml というXMLドキュメントがあります[appName].application
。これは、クライアントが現在のバージョンと比較するために使用するサーバー側のマニフェスト ファイルです。このドキュメントには、クライアントが実行している必要がある「現在の」バージョンと、展開ファイルが存在するサーバー上の場所が含まれています。
と同じ場所に、publish.htm
「Application Files」というフォルダもあります。このフォルダーには、以前の各パブリッシュのサブフォルダーが含まれています。これらの各サブフォルダー内には、上記と同じ名前の別の XML ドキュメントがあり、[appName].application
. このファイルを (元に戻したいバージョンを含む任意のフォルダーから) コピーし、同じフォルダーpublish.htm
(2 つ上のレベル) に貼り付けます。クライアント アプリケーションが再起動すると、新しいバージョンが利用可能になったように表示され、ダウンロードして実行します。クライアントは以前のバージョンを実行します。
ClickOnce は、送信したバージョンを使用します。古いバージョンを送ると、その古いバージョンにロールバックされます。
5 月に、友人の David が、ユーザーごとにこれを行う方法についての記事を書きました。文字通り、すべてのユーザーを別のバージョンにすることができます。アプリケーションは、ユーザーが必要とするバージョンをデータベースに伝えることもできるため、理論的にはバージョンを変更してから、アプリケーションを再起動するだけで済みます。
[アプリケーションの追加と削除] に移動してアプリケーションを選択し、代わりに最後のインストールを取得することを選択できます。
これを使用して、Visual Studio 2017 で開発された clickonce アプリケーションをロールバックしました。私の場合、ルート フォルダーには 2 つのファイルしかありませんでした。1 つは [applicationName].manifest、もう 1 つは setup.exe です。
[applicationName].manifest には、現在のバージョン番号への番号参照が含まれていましたが、それぞれが publicKeyToken 値にリンクされていたため、手動で編集することに消極的でした。
そのため、ロールバックしたいバージョンを含むサブフォルダーの下の Application Files フォルダーで、ルートフォルダーにコピーした別の [applicationName].manifest を見つけました (元のフォルダーをバックアップしました)。
そしてそれだけでした。それは私にとってはうまくいき、本当に簡単な解決策でした。ただし、最低限必要なバージョンを使用していないため、影響があるかどうかはわかりません。
MAGEUIを使用して、サーバー上の以前のマニフェスト バージョンにロールバックできます。これをチェックしてください。
展開場所を見ると、バージョン番号が追加された別のフォルダーに以前のバージョンがすべて表示され、バージョン番号が追加された展開マニフェストも表示されます。
それらのいずれかの名前を現在の展開に変更することができ、次にそのアプリケーションを更新するときに、ロールバックしたバージョンにプルされます。
ClickOnce のバージョン チェック アルゴリズムを次のように理解しています。
ライブの本番サーバーでこれらのいずれかを実行する必要がありましたが、これらすべてのメモがあるのは良かったです。私の解決策は少し異なっていたので、これも修正として追加したいと思いました。実稼働環境での展開を行う前に、常に、含まれているフォルダー全体を事前にバックアップします。フォルダ構造全体を元の状態にコピーして戻すことができ、すべてが正常に機能しました。
この方法に関する注意事項:
これは、パブリッシャーURIと、デプロイメントとアプリケーションの両方の名前、バージョン言語の公開鍵トークン、およびプロセッサー・アーキテクチャーがわかっている場合に、リフレクションを介して実行できます。
以下のコードは、「coolapp.app」ClickOnceアプリケーションをロールバックしようとします。ロールバックできない場合は、アンインストールを試みます。
using System;
using System.Deployment.Application;
using System.Reflection;
namespace ClickOnceAppRollback
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
string appId = string.Format("{0}#{1}, Version={2}, Culture={3}, PublicKeyToken={4}, processorArchitecture={5}/{6}, Version={7}, Culture={8}, PublicKeyToken={9}, processorArchitecture={10}, type={11}",
/*The URI location of the app*/@"http://www.microsoft.com/coolapp.exe.application",
/*The application's assemblyIdentity name*/"coolapp.app",
/*The application's assemblyIdentity version*/"10.8.62.17109",
/*The application's assemblyIdentity language*/"neutral",
/*The application's assemblyIdentity public Key Token*/"0000000000000000",
/*The application's assemblyIdentity processor architecture*/"msil",
/*The deployment's dependentAssembly name*/"coolapp.exe",
/*The deployment's dependentAssembly version*/"10.8.62.17109",
/*The deployment's dependentAssembly language*/"neutral",
/*The deployment's dependentAssembly public Key Token*/"0000000000000000",
/*The deployment's dependentAssembly processor architecture*/"msil",
/*The deployment's dependentAssembly type*/"win32");
var ctor = typeof(ApplicationDeployment).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null);
var appDeployment = ctor.Invoke(new object[] { appId });
var subState = appDeployment.GetType().GetField("_subState", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(appDeployment);
var subStore = appDeployment.GetType().GetField("_subStore", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(appDeployment);
try
{
subStore.GetType().GetMethod("RollbackSubscription").Invoke(subStore, new object[] { subState });
}
catch
{
subStore.GetType().GetMethod("UninstallSubscription").Invoke(subStore, new object[] { subState });
}
}
}
}