C# + Nancyを使って、1つのアプリでHerokuとAzure Websitesの両方へデプロイできるように構成する

前回は、1つのNancyアプリで、ASP.NET(IIS)とSelfHostingでホスティングできるように構成してみました。

今回は、前回触れることのできなかった、OWINを使ってASP.NET(IIS) Hosting・SelfHostingでホスティングできるように構成してみます。

また、せっかくですので、HerokuとAzure Websitesへのデプロイも試してみます。

 

環境

 
具体的な流れは以下の通りです。

 

ソリューション・プロジェクトの作成

ソリューションの構成は以下とします。

プロジェクト名 プロジェクトテンプレート名 内容 プロジェクトの参照
NancyApp クラスライブラリ NancyのViewやBootstrapperを含む、メインのNancyアプリ -
OwinAspNetHosting ASP.NET 空のWebアプリケーション ASP.NET (IIS) でのホスティング設定 NancyAppを参照に追加
OwinSelfHosting コンソールアプリケーション セルフホスティング設定 NancyAppを参照に追加

 
また、それぞれのプロジェクトにインストールしたNuGetパッケージは以下の通りです(依存ライブラリは除く)。

パッケージ名 バージョン NancyApp OwinAspNetHosting OwinSelfHosting
Nancy 1.0.0 o o o
Microsoft.Owin.Host.SystemWeb 3.0.0 - - o
Microsoft.Owin.Hosting 3.0.0 - - o
Microsoft.Owin.Host.HttpListener 3.0.0 - - o
Nancy.Owin 1.0.0 - o o
Nancy.ViewEngines.Razor 1.0.0 o - -

 

NancyAppプロジェクトの実装

前回とは大きな変更はありません。概要は以下の通りです。

  • HomeModule.cs の実装
    • /で、Viewrazor.cshtmlを返す
  • Viewsフォルダ以下に、razor.cshtmllayout.cshtmlを作成
    • プロパティで、コンテンツ出力ディレクトリに常にコピーするを忘れずに
  • インタフェースIRazorConfigurationを実装したRazorConfigクラスの実装
  • Bootstrapperを追加
    • OwinAspNetのためのViewフォルダとしてbin/Views/を追加

 

OwinSelfHostingプロジェクトの実装

過去に作った経験もあるこちらのプロジェクトから実装します。

 

OWIN startup fileの作成

Startup.csとして作成します。

定型的な内容なので、Wikiのままの内容で問題ないです。

 

Program.csの修正

こちらも定型なので、Wikiのままにします。

 

定型作業

忘れずに行います。

  • NancyAppプロジェクトを参照に追加
  • 名前空間予約の構成を追加
    • netsh http add urlacl url=http://+:8765/ user=Everyone

 
この状態でOwinSelfHostingプロジェクトをスタートアッププロジェクトに指定して実行したところ、ローカルでは問題なく動作しました。

この時点のコミットはこちらです。
thinkAmi-sandbox/NancyOwinMutiHosting-sample at f1325bf247640a039ba46e2959d2ffdc53b8bda6 · GitHub

 

OwinAspNetプロジェクトの実装

OWIN ASP.NETホスティングをするアプリは初めて実装するので、公式のWikiを参考に進めます。
Hosting nancy with owin · NancyFx/Nancy Wiki · GitHub

OWIN startup fileの作成

Startup.csとして作成します。

OwinSelfHosting同様、Wikiのままの内容で問題ないです。

 

web.configの修正は不要

公式Wiki

Add the following key in web.config. (This is required for the current v1.0.1 for SystemWeb OWIN host and is likely to be removed in future versions.)

と書かれていたため、試しに変更しないでみたところ、問題なく動作しました。現在のバージョンでは大丈夫なのかもしれません。

 

定型作業

忘れずに行います。IISホスティングするので、名前空間予約の構成は不要です。

  • NancyAppプロジェクトを参照に追加

 
この状態で OwinAspNetプロジェクトをスタートアッププロジェクトに指定して実行しますが、こちらもローカルでは問題なく動作しました。

この時点のコミットはこちらです。
thinkAmi-sandbox/NancyOwinMutiHosting-sample at a16df1882e4dbcc98709c65ec4b38c47a7835342 · GitHub

 

Herokuへpushするための準備

Procfileの追加

HerokuではOwinSelfHostingプロジェクトを動作させるようにするため、以下の内容のProcfileを作成します。

web: mono OwinSelfHosting.exe $PORT

コミットはこちらです。
thinkAmi-sandbox/NancyOwinMutiHosting-sample at f8dc77ba8febdcfe7217065b74d6f969f5faff3c · GitHub

 
Herokuへpushする準備ができたので、Herokuアプリを作成します。

heroku create <your application name> --buildpack https://github.com/friism/heroku-buildpack-mono

 
Herokuへpushしますが、エラーのため失敗しました。

git push heroku master
...
remote: Errors:
remote:
remote: /tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/NancyOwinMultiHosting-sample.sln (default targets) ->
remote: (Build target) ->
remote: /tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/NancyApp/NancyApp.csproj (default targets) ->
remote: /tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets (PostBuildEvent target) ->
remote:
remote:         /tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets: error : Command '
remote: if Release == Debug (
remote: xcopy /s /y /R "/tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/packages/Nancy.Viewengines.Razor.1.0.0/BuildProviders/Nancy.ViewEngines.Razor.BuildProviders
.dll" "/tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/NancyApp/bin/"
remote: xcopy /s /y /R "/tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/packages/Nancy.Viewengines.Razor.1.0.0/lib/Net40/Nancy.ViewEngines.Razor.dll" "/tmp/build_49da07c3d7fa4cb8a53b8ed52f2323c7/NancyApp/bin/"
remote: )' exited with code: 2.
...

 
Nancy.ViewEngines.Razor.dllのビルドでエラーが起きているようなので調べてみたところ、公式のIssueに情報がありました。
Adding Nancy.Viewengines.Razor NuGet package breaks xbuild on mono on Ubuntu · Issue #1082 · NancyFx/Nancy

関連するIssueも見ましたが、両方ともOpenのままで解決していなさそうでした。

そのため、上記のIssueにある通り、NancyAppプロジェクトのNancyApp.csprojファイルを以下のように修正します。

...
    <!-- add for mono -->
  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <CustomCommands>
      <!-- Custom commands for Xamarin -->
      <CustomCommands>
        <Command type="AfterBuild" command="cp -f &quot;$(SolutionDir)/packages/Nancy.Viewengines.Razor.0.17.1/BuildProviders/Nancy.ViewEngines.Razor.BuildProviders.dll&quot; &quot;$(ProjectDir)/bin/&quot;" />
        <Command type="AfterBuild" command="cp -f &quot;$(SolutionDir)/packages/Nancy.Viewengines.Razor.0.17.1/lib/Net40/Nancy.ViewEngines.Razor.dll&quot; &quot;$(ProjectDir)/bin/&quot;" />
      </CustomCommands>
    </CustomCommands>
  </PropertyGroup>
  <!-- add end -->
  
  <!-- change for mono -->
  <PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
  <!-- <PropertyGroup> -->
  <!-- change end -->
...

 
変更前後を差分で見た場合は、以下になります(左が変更前、右が変更後)。
Update NancyApp.csproj for mono environment · 143ef75 · thinkAmi-sandbox/NancyOwinMutiHosting-sample · GitHub

 
これで修正が終わりましたので、再度デプロイします。Warningが出ていますが、ビルドは成功しているようです。

...
remote: Build succeeded.
remote:
remote: Warnings:
remote:
remote: :  warning : Default tasks file /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/2.0/Microsoft.Common.tasks not found, ignoring.
remote:
remote: /tmp/build_bea67ee15cedc84bc0d8091e70476728/NancyOwinMultiHosting-sample.sln (default targets) ->
remote: (Build target) ->
remote: /tmp/build_bea67ee15cedc84bc0d8091e70476728/OwinAspNetHosting/OwinAspNetHosting.csproj (default targets) ->
remote: /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets (ResolveAssemblyReferences target) ->
remote:
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web.D
ynamicData' not resolved
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web.E
ntity' not resolved
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web.A
pplicationServices' not resolved
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web.E
xtensions' not resolved
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web'
not resolved
remote:         /tmp/build_bea67ee15cedc84bc0d8091e70476728/mono/lib/mono/xbuild/12.0/bin/Microsoft.Common.targets:  warning : Reference 'System.Web.S
ervices' not resolved
remote:
remote:          7 Warning(s)
remote:          0 Error(s)
...

 
Herokuアプリを起動してみます。

heroku open

特に問題なく動作しているようです。

f:id:thinkAmi:20150204051712p:plain

 

Azure Websites

Azure Websitesにデプロイする場合、ソースコードは特に変更する必要はないので、以下の流れになります。

  1. Azureポータルで、Websitesを作成
  2. トップの「ソース管理からのデプロイの設定」から、「ローカルGitリポジトリ」を選択
  3. Gitリポジトリの準備ができたら、その画面にある手順に従いAzure Websitesへpush

Azure Websitesでも動作しているようです。

f:id:thinkAmi:20150204051725p:plain

 

ソースコード

最終的なものはこちらです。
thinkAmi-sandbox/NancyOwinMutiHosting-sample · GitHub

 

デプロイボタン

リポジトリapp.jsonazuredeploy.jsonの2つのファイルを追加してあるため、デプロイボタンでそれぞれにデプロイを試せます。

Heroku

Deploy

 

Azure Websites