Visual StudioでC#などを書いていると、データベースの接続設定
などアプリケーションで利用する値を外部ファイルに外出ししたくなることが多々あります。この時利用するのが アプリケーション構成ファイル データベースの接続設定
です。
さてこのApp.configですが、コンソール/WPFアプリでもビルド構成によって変えたりできることは良く知られています。そう、ASP.NET MVCなどWebアプリケーションで行う、web.configのConfiguration Transformと同様のイメージです。
本記事では、WebアプリケーションでなくともConfiguration Transformを利用する方法について見ていきましょう。
- Configuration Transform を行うパターン
- ビルド構成に応じたConfiguration Transform
- ビルド構成に依存しないConfiguration Transform
- まとめ
Configuration Transform を行うパターン
紹介するのは、2つの方法です。
- ビルド構成に応じた Configuration Transform
- ビルド構成に依存しない Configuration Transform
1は有名な方法なのでサクッと行きます。
実は、2をやりたいと思ったのですが見つけられなかったのです。そこで.csproj
をいじってできるようにしてみました、というのがこの記事の本題。
両方とも、App.configのConfiguration Transformをやりたいという目的は変わらず、やるためのトリガーが違います。それぞれ使い所を適切に選択すると便利だと思います。
ビルド構成に応じたConfiguration Transform
ググると .csprojを編集することが多いのです。が、これをGUIでさくっとやるための素晴らしいVS拡張があります。
- SlowCheetah
- Configuration Transform
https://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
https://visualstudiogallery.msdn.microsoft.com/579d3a78-3bdd-497c-bc21-aa6e6abbc859
両方とも同じことができるので、今回はConfiguration Transform
をVS2015で使ってみます。
VS2015 で利用するためには
どちらのVS拡張も2013までしか現在対応していません。
このため、ダウンロードしてインストールしようとしてもVS2013までしか入らないように見えます。
vsixmanifestをいじることでVS2015にムリヤリインストールも可能です。が、あくまでもライセンスが問題なければという条件下です。
今回は、両方のプロジェクトともにApache 2.0だったので問題ないと判断して紹介します。が、十分ライセンスに留意しないといけないと思います。*1
.vsixmanifestの変更
.vsix
は.vsix
同様Zipで固めただけなので解凍すれば中身が見えます。あとは、.vsixmanifestの対象プラットフォームをちょちょいといじるだけです。この方法は、@neueccに教えてもらいました。ありがとうございますありがとうございます!
解凍したら、extension.vsixmanifest
を開いて
SupportProductにVS2015を足すだけです。
VS2015は、 VisualStudio Versionが14.0なので以下を差し込むことになります。
<VisualStudio Version="14.0"> <Edition>Ultimate</Edition> <Edition>Premium</Edition> <Edition>Pro</Edition> </VisualStudio>
manifestを更新したら、再びファイルをZipで固めて拡張子を.vsix
にします。
これでVisual Studio 2015にインストールできるようになりました。
VSを再起動すれば、インストールしたVS拡張が利用できるようになります。
PowerShell で自動化してみる
PowerShell 5.0で追加されたCompress-Archive
の秘孔をついてしまうので7zipを使うか自分でZipを書いてください。
使い方
詳しい説明は、id:tanaka733さんの素敵な記事を見るといいでしょう。ここでは記事の内容がイメージしやすいように簡単に触れます。
https://tech.tanaka733.net/entry/configuration-transform-visual-studio-extension
Slow CheetahもConfiguration Transformもほぼ変わりません。ビルド構成ごとにTransformしたいプロジェクトのApp.configを右クリックして、Add Transform とすれば実行時点のビルド構成に応じた App.<ビルド構成>.Config が生成されます。
SlowCheetah の例
Config Transform の実施
てきとーにコンソールアプリケーションを作って試してみます。
Configuration Transform のVS拡張をいれた後に、App.configを右クリックするとAdd Config Transform
が追加されています。
ビルド構成は、標準のDebugとReleaseのみです。
この状態で、Add Config Tranform
すると、ビルド構成に応じたAdd Config Tranform
が生成されました。
Config Transform の記述
早速、Configuration Transformの変換構文に従って変換を書いてみましょう。
https://msdn.microsoft.com/ja-jp/library/vstudio/dd465326.aspx
App.configとApp.Debug.configとApp.Release.configはこんな感じで、hogeというキーの値をビルド構成ごとに変更してみます。
変換結果のプレビュー
変換結果はビルドせずともPreview Config Transform
を実行することでプレビューできます。
たとえば、App.Debug.configの変換がうまくいったかみてみると? うまく変換されましたね。
ビルドで変換を確認
早速DebugとReleaseビルドを行って
結果を見てみましょう。
まずはDebugビルドです。
<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> <appSettings> <add key="hoge" value="Debug"/> </appSettings> </configuration>
つぎにReleaseビルドです。
<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> <appSettings> <add key="hoge" value="Release"/> </appSettings> </configuration>
いかがでしょうか? ビルド構成に応じてapp.configの内容が変わるのでテスト環境、本番環境など切り替えが容易になりますね。
ビルド構成を追加したら?
Hoge
というビルド構成を追加してみます。
先ほどと同様にAdd Config Transform
をすれば、App.Hoge.configが追加されます。
あとは、Config TransformをApp.Hoge.configに書くだけです。
.csproj にはどのような変更が加えられているのか
VS拡張がやっているのは、.csprojへの変更とApp.<ビルド構成>.configのテンプレート生成だけです。
重要な.csproj
の差分をみてみましょう。
これがConfiguration Transformが追加した内容です。
ポイントは、4行目の$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll"
の参照追加です。Web.configの変換でも利用しているこれを使って、Transform構文での変換を行っています。
これらの変換はビルド成果物パスであるbin
で直接行わうことはなく、中間出力パスbin
つまりbin
で実施されます。 bin
でapp.configをTransform構文に応じて変換して、最後にMSBuildがbin
からbin
にコピーするので変換されるので変な副作用がないのですね。なるほど。
また、Web.configはビルド時変換とデプロイ時変換の2段構えです。が、App.configの変換はビルド時変換のみなのも違いです。
単純ですが .csprojに仕込むことで意識せず自動化されるので非常に強力だと思います。
ビルド構成に依存しないConfiguration Transform
ビルド構成に応じたApp.configの変換はわかりました。VS拡張もあるので簡単で便利です。
しかし、ビルド構成が複数あるプロジェクトだと困ることになるケースがあるので見てみましょう。
実際どんなシーンが困るの?
自分だけのプロジェクトで、ビルド構成を沢山作っていても問題になることはまずないでしょう。
困るのは「ビルド構成を独自に増やしているプロジェクトに外部プロジェクトをプロジェクト参照した時」です。そのため、GitHubでのSubmoduleによるプロジェクト参照などはまさに困るケースになりかねません。
ASP.NET MVCのWeb.configの場合は、変換を容易に組めるので大した問題はないのですが、コンソールアプリケーションだと標準ではConfiguration Transformがないので困るのですね。
.csproj指定でのMSBuildビルド時に怒られる
私が困ったのは、ProjectAにプロジェクト参照でProjectB/Cを追加しているケースでした。
SolutionA ┣ ProjectA ┗Submodule ┣ ProjectB ┗ ProjectC
ProjectAがビルド構成をDebug/Relase/Hoge と3つ持っています。ProjectB/ProjectCはビルド構成をDebug/Releaseの2つしか持っていない状況で考えてください。
Project AをHoge
ビルド構成でビルドすると
- VSでのビルドは通ります
これは、VSはソリューション単位でのビルドが可能で、ProjectAがHoge
ビルド構成の時に、ProjectB/CはHoge
ビルドなどHoge
とは異なるビルド構成を使うか選択できるためです。
- 一方で、MSbuildで
.csproj
を指定した.csproj
ビルドは失敗します
エラーは次の通りです。
原因は The OutputPath property is not set for project 'ClassLibrary1.csproj'.です。理由は明確で、今回はClassLibrary1,2共に、Hoge
ビルド構成がいため「Hoge
ビルド構成にHoge
はない」のです。
MSBuildで.csproj
を指定してビルドすると、ProjectAが.csproj
ビルド構成の時、ProjectB/Cは.csproj
ビルドを使うという判断がつきません。これがProjectAをHogeビルドした時に、Project B/Cで怒られる原因です。
回避方法は単純で、ProjectAにHoge
ビルド構成がある場合、ProjectB/Cにも同様にHoge
ビルド構成を追加して、ビルド構成を一致させれば問題ありません。
もちろん、MSBuildでもソリューションファイル.sln
を指定してビルド実行すればビルドできます。しかし.sln
指定では、ビルドしなくてもいいプロジェクトを含む全プロジェクトがビルドされてしまい、無駄にビルド時間が伸びることがあります。*2
そこでMSBuildでは、指定したプロジェクトだけビルドされるように「対象プロジェクトの.csproj
を指定」したい、この時にビルド構成が一致しないと怒られるのです。はい。
ビルド構成を追加しなくない
ProjectB/Cを他のアプリケーションでも参照している場合、ProjectAのためだけにビルド構成を追加するのは嫌ではないですか? 私は嫌だったので、ビルド構成を使わずにMSBuildでApp.configできる方法をさがしました。
それが、MSBuildでビルド時に独自のパラメータを渡してApp.configを変換する方法です。
独自のビルド時パラメータでApp.configを変換する
VS拡張Configuration Transform がどのようにApp.configを変換しているかは学びました。であれば、これを応用するだけの簡単なお仕事です。
以下を、ビルド元の .csproj (サンプルならConsoleApplication2.csproj)に追加すればokです。
.csprojを編集後、MSBuild実施時に「Releaseビルド構成、BuildTargetにHogeを指定」を意味する、以下のパラメータでビルドします。
/p:Configuration=Release,BuildTarget=Hoge
するとビルド構成はRelaseビルドを使いつつ、 App.configはApp.Hoge.configの内容に応じてビルド時コンフィグ変換されています。
App.Hoge.configの内容に応じて
ビルド時変換で、ConsoleApplication2.exe.configも変換されていますね。
対応できるビルドパターン
先ほどのConfiguration Transformと合わせることで、次の3つのビルドパターンに対応しています。
ビルド構成 | 内容 |
---|---|
VS での通常のビルド | ビルド構成で App.configが App.$(Configuration).config と切り替わる |
MSBuild で Configurationを指定してビルド | 1 の VS と同じ挙動 (全プロジェクトに ビルド構成を用意する必要がある) |
MSBuild でトリガーとなる BuildTarget を指定してビルド | Release ビルドの状態で BuildTarget を指定すると、App.config が App.$(BuildTarget).config と切り替わる |
この対応をいれることで、ASP.NET MVCなプロジェクト同様、MSBuildからの .csproj指定ビルドでもビルド構成をReleaseのままでビルド時のApp.configのConfiguration Transformが可能になります。
VS 拡張
この .csprojの変更、面倒です。
嘆いていたら、id:tanaka733さんが、上記 .csprojの変更をVS拡張でできるようにしてくれました! やったー!
ぜひ利用していただけると!
まとめ
MSBuild勉強会してほしいお。