DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Click Once配布でのバージョン更新を完全なものにしたい

環境/言語:[.NET]
分類:[.NET]

Click Onceによる配布について質問があります。

Click Onceでは、基本的には「オンライン/オフライン・モード」か
「オンライン・モード」かの2択になるかと思います。

これから、「オンライン/オフライン・モード」での業務アプリ発行
しようと考えております。発行するアプリケーションは都度
バージョンアップを行うので、VSのプロジェクトの「発行タブ」
で「インストールフォルダのURL」を設定し、アプリケーションが
起動時にバージョンの自己確認・自動更新がされるようにしようと
思います。

ここで問題が出てくるのですが、オンライン/オフライン・モードでは、
もし、オフラインで起動した場合(つまり、何らかの理由でインストール
フォルダ・URLに接続できなかった場合)は、自動更新されない、つまり
「古いバージョンを古いままユーザーに使わせてしまう」という点です。
 これでは、管理者が「必ず最新のバージョンを全ユーザーに対して、行きわ
たらせたい」と思ってもそれが不可能ということになります。

そこで、アプリケーション自身に自己確認のロジックを持たせようと思います。
つまりアプリケーションの発行バージョンNOを下記コードで取得し、

System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString

これを元に、バージョン判定を行い、古いバージョンのままで開かれた場合、
Application.Exit コールで終了するようなロジックを設けようと
思います。(判定の基準となるバージョン番号はリリースごとにDB内に手動で
記述し、これをアプリに見に行かせるという手間のかかる方式になりますが。)


Click Onceによる完全なバージョンの統制(最新を必ず開かせる)という
ことを目指そうとすると、このような方式を取らざるを得ないのでしょうか?
それとも私が何か見落としている方式があって、本当はもっと簡単に行くのでしょうか?
 宜しくお願いいたします。

※なお、オンライン・モードでの配布なら即解決するとの見方もありますが、
オンライン・モードだと:
 @Web発行の場合、URLを一度開いてリンクをクリックする手間が発生。
 Aファイルサーバー上に発行した場合、ユーザーへのアクセスの説明が煩雑に。
 Bそもそも、オンラン・モードでの配布は、使用頻度の低いアプリケーション
  を、(余計な)クライントインストールを発生させることなく、利用させる
  ための方式なので、日常業務のアプリ配布でこの方式を用いるのは変。
 と考えています。  

ちなみにここまでの現状の分析には
http://www.atmarkit.co.jp/fdotnet/clickonce/clickonce03/clickonce03_01.html
を参考にしました。
■No30778に返信(kane123さんの記事)
> そこで、アプリケーション自身に自己確認のロジックを持たせようと思います。
Web にはアクセスできず、DB にはアクセス可能という状態を
想定しているということでしょうか。

起動時の最新版チェックをより厳密に行いたいのであれば、プログラムから
ApplicationDeployment.CheckForUpdateAsync メソッドを呼び出しては
如何でしょう。通信エラーなら、CheckForUpdateCompleted イベントにて
e.Error が DeploymentDownloadException を返すかと思います。


> これを元に、バージョン判定を行い、古いバージョンのままで開かれた場合、
> Application.Exit コールで終了するようなロジックを設けようと
旧バージョン時に無条件に Application.Exit で強制終了させる前に、
ApplicationDeployment.UpdateAsync で再度更新を試みるかどうかを
問い合わせるメッセージを表示するのも良いかも。


> このような方式を取らざるを得ないのでしょうか?
バージョン番号を比較するとのことですが結局のところ、
DB に確認に行くか Web に確認に行くかの違いしかないと思いますし、
そもそも今回の方法で万全かどうかというと少々疑問です。

今回、どこまでの対処を必要としているのかは第三者なのでわかりませんが、
たとえば、バージョンチェックの確認処理は起動時だけでよいのでしょうか。

起動時だと、アプリを立ち上げたまま何日も放置されているクライアントや、
アプリ更新の5分前に起動されたアプリは古いままになりえますよね。

そのような場合に対処するなら、起動時にチェックする手法ではなく、
たとえば数時間おきにチェックするなどの対処が必要かも知れません。
<expiration maximumAge="2" unit="hours" />
http://msdn.microsoft.com/ja-jp/library/t7050f3w.aspx

その他の手法としては、WCF なり .NET Remoting なり Socket 通信なりを通じて、
アプリが更新された時に、実行中のアプリに対して更新要求の通知を発行するとか。


あるいは、何らかのデータ通信を行うたびに、バージョン確認させる手もあります。

たとえばアプリに直接 DB サーバーと通信させるのではなく、データの読み書きを
XML Webサービス経由で行うようにしておき、SOAP ヘッダー等にて
バージョン確認も行うようなカスタム認証の仕組みを用意しておけば、
アプリとしては Web アクセスを保証するだけですむかも知れません。

データ通信を XML Web サービスに一任した場合は、Web サーバー側で
アクセスログを取れば、旧バージョンのアプリを使い続けているクライアントの
IP アドレスを後追いで調べることもできそうです。
>>そこで、アプリケーション自身に自己確認のロジックを持たせようと思います。
> Web にはアクセスできず、DB にはアクセス可能という状態を
> 想定しているということでしょうか。

その通りです。

> 起動時の最新版チェックをより厳密に行いたいのであれば、プログラムから
> ApplicationDeployment.CheckForUpdateAsync メソッドを呼び出しては
> 如何でしょう。通信エラーなら、CheckForUpdateCompleted イベントにて
> e.Error が DeploymentDownloadException を返すかと思います。

これを元に実装・テストまで行い、成功ました。望んでいる通りの展開ができそうです。大変ありがとうございました。なお、コードは、
http://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.checkforupdatecompleted(v=vs.90).aspx

にあるサンプルを修正する形で適用して、成功しました。


> 起動時だと、アプリを立ち上げたまま何日も放置されているクライアントや、
> アプリ更新の5分前に起動されたアプリは古いままになりえますよね。

おっしゃる通りです。この辺については運用面とすりあわせして決めようと
思います。

> そのような場合に対処するなら、起動時にチェックする手法ではなく、
> たとえば数時間おきにチェックするなどの対処が必要かも知れません。
> <expiration maximumAge="2" unit="hours" />
> http://msdn.microsoft.com/ja-jp/library/t7050f3w.aspx

この実装も非常に興味深いです。今回のケースでは適用する必要は
無さそうですが、機会があれば是非試したい方法です。

> その他の手法としては、WCF なり .NET Remoting なり Socket 通信なりを通じて、
> アプリが更新された時に、実行中のアプリに対して更新要求の通知を発行するとか。
>
>
> あるいは、何らかのデータ通信を行うたびに、バージョン確認させる手もあります。
>
> たとえばアプリに直接 DB サーバーと通信させるのではなく、データの読み書きを
> XML Webサービス経由で行うようにしておき、SOAP ヘッダー等にて
> バージョン確認も行うようなカスタム認証の仕組みを用意しておけば、
> アプリとしては Web アクセスを保証するだけですむかも知れません。
>
> データ通信を XML Web サービスに一任した場合は、Web サーバー側で
> アクセスログを取れば、旧バージョンのアプリを使い続けているクライアントの
> IP アドレスを後追いで調べることもできそうです。


この辺のご提案に関しては、私の知識が追いつきませんので試したくても
試せなく、お恥ずかしい限りですが、いつかトライしてみたく思います。

本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板