Visual Studio で C#など を書いていると、データベースの接続設定
などアプリケーションで利用する値を外部ファイルに外出ししたくなることが多々あります。この時利用するのが アプリケーション構成ファイル App.config
です。
さてこの 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
visualstudiogallery.msdn.microsoft.com
visualstudiogallery.msdn.microsoft.com
両方とも同じことができるので、今回は Configuration Transform
を VS2015 で使ってみます。
VS2015 で利用するためには
どちらのVS拡張も2013 までしか現在対応していません。
このため、ダウンロードしてインストールしようとしても VS2013 までしか入らないように見えます。
vsixmanifest をいじることで VS2015 にムリヤリインストールも可能です。が、あくまでもライセンスが問題なければという条件下です。
今回は、両方のプロジェクトともに Apache2.0 だったので問題ないと判断して紹介します。が、十分ライセンスに留意しないといけないと思います。*1
.vsixmanifestの変更
.vsix
は nupkg
同様 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 さんの素敵な記事を見るといいでしょう。ここでは記事の内容がイメージしやすいように簡単に触れます。
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
すると、ビルド構成に応じた App.<ビルド構成>.config
が生成されました。
Config Transform の記述
早速、Configuration Transform の変換構文に従って変換を書いてみましょう。
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
で直接行わうことはなく、中間出力パス $(IntermediateOutputPath)
つまり /obj
で実施されます。 /obj
でapp.config を Transform構文に応じて変換して、最後に MSBuild が /obj
から /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 は Release
ビルドなど Hoge
とは異なるビルド構成を使うか選択できるためです。
- 一方で、MSbuildで
.csproj
を指定したHoge
ビルドは失敗します
エラーは次の通りです。
原因は The OutputPath property is not set for project 'ClassLibrary1.csproj'.です。理由は明確で、今回はClassLibrary1,2 共に、Hoge
ビルド構成がいため 「Hoge
ビルド構成にOutputPath
はない」のです。
MSBuild で.csproj
を指定してビルドすると、ProjectA が Hoge
ビルド構成の時、ProjectB/C は Release
ビルドを使うという判断がつきません。これが 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 勉強会してほしいお。