一意キー制約は将来の機能

Entity Frameworkではじめて一意キーにリレーションを貼りたくなったのだけど、それは将来の機能だと知りました。開発チームが言及しているので、近い将来に正式サポートがされるかなあ。

このところCode Firstの機能ばかりが充足していたので、DB Firstな僕としてはあまり嬉しい機能はなかったのだけど、将来の機能には期待したい。今年の6月に次世代EFのCTPがでていて、一部の機能は先行して試せるのだけど、このなかで嬉しそうなのはダイアグラムの分割ですかね。いまテーブルが増えすぎてえらいことになっているので。Enumと空間型もなくてもいいけど、あったら楽な機能なので、いずれにせよはやいところリリースして欲しい。段階リリースとかはあり得なさそうなので、入れるなら全部入りになるのかしら。

そういえばぜんぜん関係ないけど、WPF Toolkitはもう出ないのでしょうかね。グラフとかのコントロールを正式に出して欲しいんだけどなぁ。

自動更新ライブラリを比較する(その2)

昨日の記事を書いたあとで見つけたいくつかのアップデートフレームワークを紹介します。

wyUpdate

オーナーのサイトが有償ぽかったのでスルーしていましたが、有償なのはwyUpdateライブラリを含むmyBuildというライブラリのほうで、wyUpdate自体はオープンソースのようでした。ライセンスは修正BSDライセンス。なのでこれも著作表示がしてあれば商用でも使えますね。AutomaticUpdater というUIコントロール別途配布しているようです。WPF版もあります。ただ、こっちはLGPLのようなので商用利用時の改変には注意が必要です。

wybuild機能一覧の中程にmyUpdateの機能が書いてありますが、これを見ていると

  • VCDIFF delta-patchフォーマットでのパッチ適用
  • UAC対策
  • 制限付きユーザ対策
  • プロキシ対応(カスタムプロキシもOK)
  • ファイルパーミッション対策

なんかが書いてあります(対策とあるのが具体的に何ができるのかまではちゃんと見てません)



商用ライブラリwyBuildを同時に開発しているだけあって、商用ソフトをつくっているとたびたび直面するような問題に対してケアがありそうなのがいいですね。プロキシもコマンドラインでの対応というのはちょっとアレですが、カスタムにちゃんと対応しているのは商用向きだと思います。ほかにも、たとえばClickOnceだと1ユーザにしかインストールできなかったのですが、Wix+wyUpdateで全ユーザにインストールできそうで(ファイルパーミンションとか制限付きユーザ回りの対応はそのへんかと推測)、これもユーザが必ずしも管理者でない可能性がある商用アプリで使える機能かと思います。

資料がwyBuildとまざっちゃっていて探しにくいという面はありますが、まあ、ライブラリ自体はそう難しいものでもないでしょう。

更新も頻繁ですし、これはいいかも。

DDay.Update解説ページ

DDay.Updateが面白いのは、更新定義ファイルにClickOnceマニフェストファイルをそのまま使っているところでしょうね。これだと乗り換えの人にとってはやりやすい気がします。

最終更新が2010年の11月で、それもコメント修正程度、本体のコードの更新は2010年3月までさかのぼり、メジャーリリースは0.72.1が2009年1月ですね。今後の更新にはすこし不安は残ります。ライセンスはCOPL(CodeProjectのライセンス)なので商用で使えますね。

Updater

 この記事内ではまだCOPLですが、最新版は現在、有償ライブラリになっている模様(サイト)なので、あまり熱心に見ていません。

自動更新ライブラリを比較する

ClickOnceはどうも制限が多すぎるので、自動更新ライブラリを比較してみようと思います。ぱっと見有望そうなのは

かな。メモを追記していきます。とりあえず適当に文章で書いておこう。

ライセンス

どっちも商用利用は出来そう。

NuGet対応

どっちもしてないです。管理主体がNetSparkleはCodePlexでNAppUpdateはgithubだから、NetSparkleが先に対応しそうな勝手なイメージはあるけど。

UI

  • NetSparkleはライブラリ自体がUIを持っていて、更新履歴とかを出してくれる。多言語対応している。
  • NAppUpdateはライブラリは更新フレームワークのみ。サンプルとしてUIをつかったものは同梱されてた。

その他

ひとつずつ比較しにくいので、とりあえず、機能一覧を抄訳してみようかな。

NetSparkle機能一覧より

  • Windowsインストーラベースを必要とする更新ではなく、単体で更新機能を提供する
  • リリース情報を通知できる
  • IEコントロールを使って、更新ニュースを表示できる
  • 更新経過をユーザに通知できる
  • アプリケーション側にはコードを追加しなくても良いので、モジュールの更新削除はとても簡単
  • NetSparkleへの言及はなく、アイコンやアプリ名が自由に使える
  • DSA書名による高セキュリティなアップデートをサポート
  • スタートメニューを開発するためのUpdateChecker-Helperを持つ
  • 多言語対応

NAppUpdate機能一覧より

  • ライブラリは1DLLにまとまっており、.NET 2.0以上さえあればよし。
  • コールドアップデートをサポートしていて、実行中に準備をし、置き換えられないファイルがあってもリスタート時に置き換えてくれる。
  • 更新チェックや更新準備などのタイミングを好きなように設定できる。ロールバックできる。
  • アップデートはタスクとして表現されていて、現在はFileUpdateTask(ファイルをダウンロードして置き換える単純なタスク)のみが実装されている。インタフェースを実装すればオリジナルのタスクが追加できる。たとえば、レジストリのアップデート・データベースのアップデート(スキーマ更新・データ更新)、Luceneインデックスの更新、Diff形式のパッチなどなど。
  • タスクレベルでバックアップとロールバックがサポートされる。
  • 条件付きアップデートが出来る。すべてのタスクに条件を付けられる。条件に合わないタスクは無視される。この条件も、オリジナルの実装が可能。
  • 条件タイプがサポートされている。ファイルの存在チェック、バージョン、サイズ、日付、チェックサム、OSビット、レジストリのチェック、OSのチェック、.NETバージョンのような他の事前条件のチェックなどもできる。
  • Feedフォーマットは、Adobe Appcast形式と、オリジナルなNauXMLの二つをサポート。IUpdateFeedReaderを実装すれば、オリジナル形式も可能。
  • ソースのダウンロードも抽象化されている。規定でSimpleWebSourceとMemorySourceが実装されている。

まとめ

サイトとサンプルを見ての印象

  • NetSparkle
    • 暗号化に対応
    • 多言語対応しているがUI自体がライブラリに含まれてるのは余計な気がする
    • CodePlex なので .NET開発者に発見されやすい気がする
    • 更新はそれなりに頻繁にされてる。
  • NAppUpdate
    • コンパクトで、拡張性を考えると筋が良さそうなイメージ
    • バージョンがまだ若くて、これから更新が進んでくれるのかどうかは少し不安(僕が貢献できればそれに越したことはないが)。
    • CodePlex にくらべ .NET開発者には見つかりにくそう
    • 更新はそれなりに頻繁にされてる。

DebugとReleaseでApp.configを切り替える(その2:XDT 編)

あれ、震災後まだ一回も更新してなかったですかね(読んでる人はわずかでしょうけど) 

以前の記事で propertyGroup のなかに appConfig タグを入れて設定ファイルを切り替える方法を書きました。このやりかたはシンプルですが、AppConfig をまるごと差し替えるので、ファイルの内容が多くなると両方に同じ記述を転記したりしなければならないなどメンテが面倒な感じになります。

実はWebアプリであれば、面白い仕組みがあります。Web.configというファイルとは別に、Web.debug.config と Web.release.config という元のファイルを変換するxmlを定義することで、ビルド後の配置するときに Web.confg を適切なものに差し替えるという仕組みですね。この変換するためのしくみが XML Document Transform (XDT) です。ただ、Visual Studio 2010のばあい、デフォルトでは、Webアプリのビルドの時にしか作動していないようです。

これを、AppConfig でもできるようにするやり方を書いている記事を見つけました。Vishal Joshi's Tangent: Applying XDT magic to App.Configです。大変親切に書いてあるので、このままやれば出来ますが、例によって英語で読むのが面倒だという人のために概略を紹介します(すいませんが、C#のプロジェクトを前提にしてます)

1. ベースとなる app.config の作成

WPFやWinFormプロジェクトを作成し、 app.config を次のように記述します。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="hoge" value="aaaa" />    
  </appSettings>
</configuration>
2. 変換する app.debug.config の作成

プロジェクトに app.debug.config を追加し、次のように記述します。

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add key="hoge" value="bbbb" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
  </appSettings>
</configuration>

この記述は app.config から hoge というキーをもつ add 要素を探して(xdt:Locator="Match(key)")、value属性を bbbb でおきかえよ(xdt:Transform="Replace")という意味ですね。

3. プロジェクトファイルの Include の変更

プロジェクトファイル(*.csproj)を編集します(プロジェクトを「アンロード」すると、プロジェクトのコンテキストメニューに「編集 hogehoge.csproj 」というメニューが出るので、VS上で編集できます。しばらくこれに気がつかず、VS環境外からテキストエディタを使ってました……)

configの記述を探します。

<None Include="app.config" />
<None Include="app.debug.config" />

これを

<Content Include="app.config" />
<Content Include="app.debug.config" >
    <DependentUpon>app.config</DependentUpon>
</Content>

こう書き換えます。なお、NoneをContentに書き換えることについて、原文には「This is a tiny pre-requisite for WPP but if you encounter any issues because of this then we can dig the work around…」(これはWPF向けに必須ですが、これが原因で問題が起きた場合は他に何らかの回避方法があると思います)とありましたので、WinFormだとNoneのままでもいいのかもしれません。僕はWPFプロジェクトだったので書き換えてやっています。問題は出ていません。

4. ProjectConfigFileName の追加

プロジェクトファイル(*.csproj)のPropertyGroup の配下に ProjectConfigFileName 要素を追加します。

<PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{2D587604-866B-4675-8587-FA9728EC59D8}</ProjectGuid>
    <ProjectConfigFileName>App.Config</ProjectConfigFileName>
5. Import の追加

プロジェクトファイル(*.csproj)の

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

というタグの下に

  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

を追加します(二行目は、引用元の記事の本文には追加指示がありませんが、コメント欄で指摘されています。二行目がないとビルドエラーになります)

6. Target の追加

VS 2010で作成したプロジェクトファイル(*.csproj)には、

  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->

というコメントアウトされている部分があります。この後ろあたりに次のように記述します。

  <Target Name="PostTransformAppConfig" AfterTargets="Build">
    <CallTarget Targets="TransformWebConfig" />
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).exe.config" />
    <Copy Condition="Exists('$(TransformWebConfigIntermediateLocation)\transformed\App.config')" SourceFiles="$(TransformWebConfigIntermediateLocation)\transformed\App.config" DestinationFiles="$(OutputPath)\$(AssemblyName).vshost.exe.config" />

 ビルドが終わった後(AfterTargets="Build")に、TransformWebConfigをつかってAppConfigを変換()、その後、transformedに書き出されている変換後のファイルをリネームしつつ、アセンブリ名.exe.configと アセンブリ名.vshost.exe.config を差し替えます。

7. ビルド

これでビルドすれば、configファイルは適切に差し替わると思います。

8. 注意

AfterTargets="Build" は MSBuild 4.0 からできるようになった記述ですが、これをすると、ビルドイベント実行後(PreBuildEventより後)に作業が行われるため、たとえばビルド後にコマンドラインでファイルをアーカイブするような記述を書いていても、変換結果がアーカイブに入ってくれません。

仕方ないので、PreBuildEventに書いていたコマンドラインを PostTransformAppConfig 自体に追記することにしました。Exec タグで Command 要素を使えばコマンドラインはそのままターゲット内にかけるので、単純なものならそれで十分でしょう。条件分岐などが必要なビルドイベントは、バッチファイルをつくって呼んだ方が良いかもしれません(マクロ展開が面倒ですが)。

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

前回の記事で「ただ、一回目のインストールだけは当然できないので、CDかイメージからのインストールを行って、更新URLを設定しておく必要があります」と書きました。このときは未検証のまま、一回目のインストールをローカルに発行し、更新URLを設定すれば、初回はローカルからインストールされ、あとはソフト起動時にプロキシ経由で更新ができると漠然と思っていたんですが、どうもうまくいきません。実は初回インストール時にローカルからインストールしても、更新URLが存在していると初回にアクセスして確認をしようとするらしく、結局プロキシを越えられないためにエラーになってインストールに失敗してしまうのです。これは予想外の動作でした。


なので初回のClickOnceインストールからすべてを自作することで、更新時と同じようにWebRequestに認証情報を含めてのインストールを行う必要があります。カスタムインストーラの作り方については、MSDNの「Walkthrough: Creating a Custom Installer for a ClickOnce Application - Visual Studio 2015 | Microsoft Docs」に記述がありました。このやり方と前回の記事にある更新時のプロキシ設定の仕組みを、初回インストール時にも適用するよう、インストーラを自前で作り直せばよい、ということです。インストーラまで自作しなければならないというのはけっこう面倒ですが……。


僕の場合、カスタムインストーラは普通にWindowsFormプロジェクトを作って対応しています。アンインストールとかはClickOnce自体が取り持ってくれるので、インストーラとは言いながら入力フォームがあればすむので……。

プロキシ認証が必要な環境下での、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を設定しておく必要があります。それはそれで面倒なんですが、更新時にプロキシ認証を越えられるだけでも使えるケースはあると思います。 すいません、これはダメでした。次の記事を参照してください。

SQL Server CE 4 がリリース

いつのまにか SQL Server CE 4 がリリースされてた。

Download Microsoft SQL Server Compact 4.0 from Official Microsoft Download Center

現在作っているソフトウェアでは容量制限で SQL Server のExpress につっこむのをあきらめ一部バイナリで保存しているデータがあるのだけど、当然の如く検索性が最悪なので、取り回しがめんどうなことになっている。ここが置き換えられるか、どっかで検証したいなあ。パフォーマンスが実用的なレベルで収まるのかが気になる。