プロキシ認証が必要な環境下での、ClickOnceによるアプリケーション更新

最新のClickOnceでプロキシ認証は、Windows認証のみ対応しているとされています。それ以外のプロキシ認証が必要な環境では、ローカルプロキシを経由するなどの方法を使う必要がありました。ただ、PCに明るくないユーザさんにローカルプロキシを入れよ、というのがなかなか難しい場合もあります。そんなわけで、それを乗り越える方法を書いているブログを見つけました。


http://bronumski.blogspot.com/2009/06/clickonce-updates-via-authentication.html


リンク先を読めば解決しますが、英語を読むのが面倒な人のためにこちらにも書いておきます。


まずは、自動でアプリケーションの更新を確認するのをやめ、コードで更新タイミングを手動制御することにします(発行画面で言うと「更新...」ボタンから「アプリケーションの更新を確認する」のチェックを外す)。


ここは通常の手動更新なので、特に変わったことはしないです。 ApplicationDeployment.CurrentDeployment で現在の ApplicationDeployment を取得して、CheckForUpdate() で更新チェック、Update() でアップデートします。Google Chromeみたいに気づいたときには更新されているのがいい場合は UpdateAsync() ですかね。

            if (ApplicationDeployment.IsNetworkDeployed) {
                try {
                    var appDeploy = ApplicationDeployment.CurrentDeployment;
                    if (appDeploy.CheckForUpdate()) {
                        Logger.Info("アップデートが検出されました。");
                        appDeploy.UpdateAsync();
                    } else {
                        Logger.Info("このアプリケーションは最新版です");
                    }
                } catch (Exception ex) {
                    Logger.Error(ex);
                }
            } else {
                Logger.Info("このアプリケーションはネットワーク経由での更新ができません。");
            }

で、このままだと、当然プロキシ認証には失敗します。


ネットワークに手を入れます。まずカスタムの WebProxy を作ります。

    public class CustomWebProxy : IWebProxy {
        private WebProxy _orginalProxy;

        public CustomWebProxy(string server) {
            _orginalProxy = new WebProxy(server);
            _orginalProxy.UseDefaultCredentials = false;
        }

        public CustomWebProxy(string serverName, int port) {
            _orginalProxy = new WebProxy(serverName, port);
            _orginalProxy.UseDefaultCredentials = false;

        }

        public void SetCredentials(ICredentials credentials) {
            _orginalProxy.Credentials = credentials;
        }

        public ICredentials Credentials {
            get { return _orginalProxy.Credentials; }
            set { } //ここで外部からのセットを無視する
        }


        public Uri GetProxy(Uri destination) {
            return _orginalProxy.GetProxy(destination);
        }

        public bool IsBypassed(Uri host) {
            return _orginalProxy.IsBypassed(host);
        }
    }

情報元のブログによれば、ClickOnce はせっかく設定した Credentials をなぜかデフォルトで上書きしてから通信を行っているようです(なんでそんなことしてるのだろう?)。なので、ここではCredentials のSetterプロパティを空振りさせます。かわりに、SetCredentialsというメソッド経由で設定するようにします。


あとはこんなのでOK。

var proxy = new CustomWebProxy("localohost", 8080);
proxy.SetCredentials(new NetworkCredential("user", "password"));
WebRequest.DefaultWebProxy = proxy;


これで、このアプリケーションから出るリクエストはすべて認証を経由します(WCFで通信を行っている場合は、それらもすべてプロキシ認証されます)。そんなわけで、ClickOnceの手動アップデートはプロキシを乗り越えられるようになりました。ただ、一回目のインストールだけは当然できないので、CDかイメージからのインストールを行って、更新URLを設定しておく必要があります。それはそれで面倒なんですが、更新時にプロキシ認証を越えられるだけでも使えるケースはあると思います。 すいません、これはダメでした。次の記事を参照してください。