銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

TopShelf と MSDeploy で作る、Windowsサービスお手軽自動展開環境

Windows上で長期間に渡ってバックグランドで動くようなプログラムを作るのに、Windowsサービスを使うことができます。

Windows サービス アプリケーションの概要

なんですが、WindowsサービスをVisual Studioにデフォルトで用意されているものだけで作ると割と面倒だったりします。これを解決するのに、TopShelfというツール(ライブラリ)があります。詳しくは以下のサイトに使い方から詳しく紹介されています。

Windowsサービスを楽に開発~TopShelf~ | 84zume Works

ここにもある通り、なにが便利かというと、普通のコンソールアプリケーションとして開発することができて、デバッグなどが用意になります。そして、面倒なWindowsサービスとしての設定の部分は、TopShelfのライブラリを参照してC# コードとして記述できることです。

こうやって作成したコンソールアプリケーションのビルド成果物(通常 bin\Release フォルダ以下に作られる exe一式)を動かすとコンソール上、そしてWindowsサービスへのインストールが簡単に実現できます。

さて、これで成果物一式はできたのですが、この成果物を特定のサーバーで動かしたくて、かつCI環境を使って、リポジトリにコミットしたら自動もしくはワンポチでそのサーバーに展開したい、という要件が出てきたとしましょう。

まず、成果物一式を特定のサーバーに転送するには、MSDeployコマンドを使うことができます。MSDeployコマンドが RoboCopy と比べて優れている点は、転送先のフォルダをUNCの共有フォルダでなくても転送できる点です。逆にデメリットとしては、ファイルを受け取る側で2つの必要なサービスをインストールして動いていないといけないことと、特定のポートが開いていないといけない点があります。以前書いたエントリでも紹介しています。

あるディレクトリ以下のファイルを MSDeploy でIIS Webサイトにデプロイする - 銀の光と碧い空

このエントリではIISのWebサイトとして~とありますが、IISとは全く関係ない、普通のディレクトリにも転送(同期)することができます。

これで自動でexeを更新できる...といいたいところですが、Windowsサービスとして動いているのでこのままではうまくいきません。サービスとして動いているプロセスがexeファイルなどをつかんでいるため、そのままでは上書きできないのです。サービスを一時停止していい場合では、この問題に対しMSDeploy の runCommand プロバイダーを使うことで解決することができます。

Web 配置 runCommand プロバイダー

操作設定 -presync および -postSync と共に runCommand を使うことによって、MSDeployによるファイル同期の前後に指定したコマンドを実行できます。この場合、サービスの停止と開始を指定してあげるとうまくいきます。

MSDeploy.exe -preSync:runCommand="net stop MyService" -verb:sync -source:dirPath="C:\Tool\bin" -dest:computerName="http://ww.xx.yy.zz/MSDeployAgentService",userName="administrator",password="password",includeAcls="False",dirPath="C:\Tools\bin"  -postSync:Command="net start MyServoce"

更新対象のexeを MyServiceというサービスで動かしている場合、このコマンドでMyServiceを止めてから同期が実行され、MyServiceを起動することになります。

という感じでこの2つを組み合わせると、割と簡単にWindowsサービスの自動展開環境を作ることができます。

そして、前回のエントリで紹介した Config Transform を使うと、展開先が複数あって設定を切り替えたい場合も、コードは1つで App.XXX.config を展開先ごとに用意することで対応することができます。

App.config の config変換をしてくれる便利すぎるVisual Studio 拡張「Configuration Transform」 - 銀の光と碧い空

App.config の config変換をしてくれる便利すぎるVisual Studio 拡張「Configuration Transform」

コンソールアプリやWPFアプリを作っていて、アプリのコードは同一だけど配置先に応じて設定を切り替えたい、ということはないでしょうか?Webアプリの場合、 Web.config を変換する仕組みがデフォルトで備わっていて、このブログでも触れたことがあります。

Web発行先に応じたconfig変換をコマンドラインでのビルドで適用する ~既知のバグもあるよ~ - 銀の光と碧い空

ところが、コンソールアプリなどで使われる App.config についてはこのような機能がありません。同様の仕組みを実現するために、ビルドイベントでファイルをいじったり、自前でビルドタスクを書いたり...といろいろな方法がWeb上にはあります。

が、今回紹介する「Config Transform」というVS拡張はほかのものと比べてかなり便利な機能が備わっています。

Configuration Transform extension

個人的に便利だと思っているのは以下の3点です。

  • 拡張機能を使うと、csproj を編集してビルドタスクを作成するので、この拡張機能に依存しない形で展開可能(CIサーバーなどこの拡張機能がない環境でもビルドできる)
  • ビルド構成ごとのconfig 変換ファイルを自動生成
  • config のPreviewもついている

一番大きいのが最初の点ではないでしょうか?自分だけがさわる環境ならともかく、CIサーバーなどを用意して共同開発して自動で展開するような環境だと、VS拡張がないとビルドできない、というものだとなかなか厳しいものがあります。しかし、この Config Transformは App.config の変換を有効にすると、csproj を編集してビルドタスクを新たに作成するため、以降はこのVS拡張がなくてもconfig変換機能が有効になります。

ただ、注意点としては、変更後のcsprojを見ると下記のように、Microsoft.Web.Publishing.Tasks.dll を参照しているのでこのdllが必要そうです。このdllを配置するおそらく一番簡単な方法は、Visual Studio Pro以上もしくはExpress for Web をインストールすることかと思われます。

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />

使い方は上のリンクのVS拡張のページに図入りであるので、すぐわかると思います。App.config を右クリックして「App Config Transforms」を選ぶと、ビルド構成に応じたApp.XXX.config が作成されます(XXXはDebugとかReleaseとか)。したがって配置する場所ごとにconfigを差し替えたい時は、配置先に応じたビルド構成を作成する必要があります*1

たとえば、ありがちな AppSettingsを差し替えたい場合はこうなるでしょう。 元のApp.configがこうなっていまして、

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <add key="Hoge" value="Fuga"/>
  </appSettings>
</configuration>

変換用のApp.Release.configをこう定義しますと

<?xml version="1.0"?>
<!-- For more information on using app.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings xdt:Transform="Replace">
    <add key="Piyo" value="NewValue!"/>
    <add key="Poyo" value="NewValue!!"/>
  </appSettings>
</configuration>

こういうふうに変換されます。(この結果はPreview機能で元のファイルとの差分としてVS上で確認可能)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <add key="Piyo" value="NewValue!" />
    <add key="Poyo" value="NewValue!!" />
  </appSettings>
</configuration>

こんな感じでなかなか便利です。

*1:発行先ごとに設定できるWeb.configと比べてちょっと面倒くさいけど、VSの仕様なのでしょうがない

VisualStudio "14" CTP4 の .NET 関連アップデート

ここにきてアップデート関連の情報が多くなっている気がしますが、Visual Studio "14" CTP4 が出ました。リンク先から飛べるダウンロードページ、もしくは AzureのImageギャラリーから利用可能です。

Announcing October 2014 Updates to .NET Framework vNext, ASP.NET vNext and .NET Native in Visual Studio “14” CTP4

.NET 関連はこんなアップデートになっています。

  • .NET Frameworkのバージョンは 4.5.3 に。RyuJIT がリリースされ、デフォルトで有効な状態*1
  • ASP.NET vNext CTP4 リリース
    • Roslynによるコンパイルの高速化
    • Nuget が ASP.NET vNext にも対応
    • プロジェクトテンプレートで新しいソリューションレイアウトが導入
    • ASP.NET vNext のUnitTestでDebugサポート
  • .NET Native
    • WCF サポート関連のバグFix
    • 特定のXAMLルート要素なしにツールの利用が可能に
    • WinMDに対してカスタムロケーションが利用可能に
    • 出力先の絶対パスのサポート

RyuJITがデフォルト有効になり、ASP.NET vNext も徐々に全貌を見せてきました。また、先月公開されたGitHubの.NET サンプルのリポジトリにも、新しいサンプルが追加されていくと書いてあり楽しみです。

Microsoft/dotnetsamples · GitHub

*1:今まではRyuJITを別にインストールする必要があって、かつ有効にするにはレジストリ設定などが必要だった