以前、Ruby + HerokuでJSONを返すWebアプリを作りました。
Ruby + Heroku + Highchartsで食べたリンゴの割合をグラフ化してみた - メモ的な思考的な
最近C#を触っているため、C#で同様なものを作る方法を探してみたところ、C# + Nancy + Herokuで実現できそうなことが分かりました。
そこで、Herokuまわりで気になっていたHeroku Buttonとともに、C# + NancyをHerokuへデプロイすることを試してみました。
環境
- Windows7 x64
- Visual Studio
- .NET Framework 4.5
- SourceTree
- Herokuのアカウントを作成済
- Heroku Toolbelt 3.11.1
- NuGetパッケージ
事前調査
Nancyとは
NancyとはRubyのSinatraみたいなもので、C#でもさくっとWebアプリを作れるものでした。
NancyFx/Nancy - GitHub
Nancyのホスト
NancyのホストとしてASP.NETなどがありますが、今回はHerokuで動かすためSelf Hostingという方法を使いました。
そこで、Self Hostingができるライブラリを調べてみたところ、
- OWIN - Microsoft.Owin.HostingとNancy.Owin
- 非OWIN - Nancy.Hosting.Self
などがありました。
OWINはRubyのRackみたいなものということで、以下を参考に勉強がてらOWINを使う方法で試してみることにしました。
HerokuでNancyを動かす方法
Herokuの3rd party buildpackを使えば、MonoでNancyを動かせそうでした。
Third-Party Buildpacks | Heroku Dev Center
buildpackはいくつかありましたが、公式よりリンクされているものを使うことにしました。現時点では、Mono 3.2.8で動くようです。
friism/heroku-buildpack-mono · GitHub
Nancyアプリの作成
以下を参考にNancyアプリを作成します。
Running OWIN/Katana apps on Heroku – Randoom
コンソールアプリケーションプロジェクトの作成
今回はSelf Hostingで動かすため、コンソールアプリケーション
のプロジェクトを作成します。
Gitリポジトリの用意
.gitignoreファイルの追加
gitignore.io のVisualStudio
テンプレートのままで問題ないので、ソリューションファイルと同じフォルダに入れておきます。
Gitリポジトリの作成
とりあえず、SourceTreeのコンソールなどでGitリポジトリを作成しておきます。
NuGetより必要なパッケージをインストール
以下の必要なパッケージをインストールします。
なお、インストールしただけでは、Herokuにpushした時にNuGetパッケージがインストールできずにエラーとなります。
そのため、ソリューションの右クリックから「NuGetパッケージの復元の有効化」を選択して、.nuget
フォルダ以下をソリューションに追加しておきます。
OWINによるNancy起動の実装
OWINを使ったNancyを実装します(Program.cs
, Startup.cs
)。ほとんど定型っぽいです。
Program.cs
特に意味はありませんが、localhostはポート9876
で待ち受けるようにしてみました。
using System; using Microsoft.Owin.Hosting; using System.Threading; namespace NancyOwinHeroku_sample { class Program { private static ManualResetEvent _quitEvent = new ManualResetEvent(false); static void Main(string[] args) { var port = 9876; if (args.Length > 0) { int.TryParse(args[0], out port); } Console.CancelKeyPress += (sender, eArgs) => { _quitEvent.Set(); eArgs.Cancel = true; }; using (WebApp.Start<Startup>(string.Format("http://+:{0}", port))) { Console.WriteLine("Running port: {0}", port); Console.WriteLine("Started"); _quitEvent.WaitOne(); } } } }
Startup.cs
定型なので、そのままです。
using Owin; namespace NancyOwinHeroku_sample { public class Startup { public void Configuration(IAppBuilder app) { app.UseNancy(); } } }
GETリクエストの処理の実装
プロジェクトにModules
フォルダを追加し、フォルダの中にGETリクエストを処理するクラス(HomeModule.cs
)を実装します。
今回は、
/
で「Hello World」を返す/json
でJSONを返す
ようにしてみました。
Modules\HomeModule.cs
using Nancy; namespace NancyOwinHeroku_sample.Modules { public class HomeModule : NancyModule { public HomeModule() { Get["/"] = _ => "Hello World"; Get["/json"] = _ => { var ringo = new[] { new { Id = 1, ItemName = "トキ"}, new { Id = 2, ItemName = "秋映"} }; return Response.AsJson(ringo); }; } } }
なお、Response.AsJson()
メソッドで返ってくるJSONレスポンスは
[{"id":1,"itemName":"トキ"},{"id":2,"itemName":"秋映"}]
のように、lowerCamelCaseでした。バージョンアップにより変更がなされたのかもしれません。
NancyFxでWebAPIを作るときに必ず参照すべきライブラリ - らびたろちゃんにっき
Procfileの追加
ソリューションファイル(*.sln
)と同じフォルダに、Herokuで使うProcfile
を用意します。
今回のアプリケーション名は「NancyOwinHeroku-sample.exe」でしたが、環境に応じてexeファイル名も修正します。
web: mono NancyOwinHeroku-sample.exe $PORT
ローカルでの動作確認
名前空間予約の構成の追加
Self Hostingの場合、ローカルで実行するには名前空間予約の構成の追加が必要になります。
HTTP および HTTPS の構成 - MSDN
PowerShellを管理者で起動し、まずは実行中のユーザーを確認します。
> whoami
次に、そのユーザーに対して、パーミッションの追加を行います。<UserName>
は、上記のwhoamiで取得したものをコピペすれば良いです。
> netsh http add urlacl url=http://+:9876/ user=<UserName>
起動と動作確認
VIsualStudioをデバッグ実行して、コンソールを起動します。
その状態で http://localhsot:9876
へアクセスし、エラーとならないかを確認します。
エラーがなければ、ここまでで実装は一段落したため、GItリポジトリにコミットしておきます。
WindowsでのHeroku環境セットアップ
Nancyアプリが完成したため、Herokuへとデプロイしますが、今まではUbuntu上でしかHeroku環境を作っていなかったため、今回新しくWindowsでの環境を作ります。
Heroku Toolbeltのインストール
以下のURLよりダウンロードします。
Heroku Toolbelt - Heroku
インストール先は、念のためデフォルトから以下へと変更しておきます。
C:\Heroku
また、インストール途中で、Custome Install
を選択するとインストール対象を選べるようになります。
今回は、Gitは手元にある & foreman使わないことから、Heroku Client
のみ選択しました。
Herokuのセットアップ
今回はSourceTreeのコンソールを使ってセットアップします。
まずはHerokuにログインします。
$ heroku login Enter your Heroku credentials. # Herokuのメールアドレスを入力 Email: <Herokuアカウントのメールアドレス> # Herokuのパスワードを入力 Password (typing will be hidden): <Herokuアカウントのパスワード> Authentication successful.
公開鍵の確認をします。
$ heroku keys
Heroku用の公開鍵が登録されていない場合、以下のHeroku向けの公開鍵設定を行います。
設定を行わない場合、「Permission denied (publickey)」などでHerokuへのpushが失敗します。
- permission denied (publickey) Error using git on windows 7 - Stack Overflow
- Herokuで鍵がPermission denied (publickey). になる時 - opamp_sando's blog
- Heroku アカウントの管理 - 君の瞳はまるでルビー - Ruby 関連まとめサイト
Heroku向けの公開鍵設定
既存の公開鍵を使いまわしても良いですが、今回はHeroku専用の公開鍵(鍵名:heroku_rsa)を用意することにしました。
公開鍵の生成
<%USERPROFILE%>
部分は自分の環境に合わせます。
$ ssh-keygen -t rsa Generating public/private rsa key pair. # 公開鍵のフルパスを入力 Enter file in which to save the key (<%USERPROFILE%>/.ssh/id_rsa): <%USERPROFILE%>/.ssh/heroku_rsa # 必要に応じて鍵に対するパスワードを設定(空白も可) Enter passphrase (empty for no passphrase):<任意のパスワード> # パスワードを再入力 Enter same passphrase again:<同上> Your identification has been saved in <%USERPROFILE%>/.ssh/heroku_rsa. Your public key has been saved in <%USERPROFILE%>/.ssh/heroku_rsa.pub. The key fingerprint is: <fingerprint> <user@pc>
configファイルの作成
今回はHeroku専用の公開鍵を用意したため、config
ファイルを作成・設定を行います。
以下の内容で、 %USERPROFILE%\.ssh\config
ファイルを作成します。
Host heroku.com User git port 22 Hostname heroku.com IdentityFile ~/.ssh/heroku_rsa TCPKeepAlive yes IdentitiesOnly yes
Herokuへ公開鍵を登録
$ heroku keys:add Could not find an existing public key at ~/.ssh/id_rsa.pub # Heroku専用の公開鍵は生成済なので、[n] Would you like to generate one? [Yn] n Found an SSH public key at <%USERPROFILE%>/.ssh/heroku_rsa.pub # 今回生成したキーなので、[Y] Would you like to upload it to Heroku? [Yn] Y Uploading SSH public key <%USERPROFILE%>/.ssh/heroku_rsa.pub... done
Herokuへのデプロイ
引き続き、SourceTreeのコンソールを使って、herokuコマンドからデプロイできるかを試してみます。
Herokuアプリの作成
アプリ名は後から変更できるため、とりあえず作成します。
$ heroku create
buildpackの設定を追加
今回使用するbuildpackを追加します。
$ heroku config:add BUILDPACK_URL=https://github.com/friism/heroku-buildpack-mono
デプロイ
$ git push heroku master Fetching repository, done. ... -----> Compressing... done, 63.6MB -----> Launching... done, v8 http://<アプリ名>.herokuapp.com/ deployed to Heroku
無事にデプロイが終わりました。
動作確認
http://<アプリ名>.herokuapp.com/
やhttp://<アプリ名>.herokuapp.com/json
へとブラウザでアクセスし、
- Hello World
- JSONレスポンス
が表示されるかを確認します。
Heroku Buttonの作成
以下を参考に、Heroku Button用のapp.json
ファイルをソリューションファイルと同じフォルダに作成します。
Deploy to Heroku / Webアプリケーションのポータビリティ再び - naoyaのはてなダイアリー
app.json
{ "name": "NancyOwinHeroku-sample", "env": { "BUILDPACK_URL": "https://github.com/friism/heroku-buildpack-mono" } }
作成が終わったら、コミットしてGitHubへpushしておきます。
次に、以下のようなHeroku Buttonを用意します。
そして、Herokuにログインした状態でHeroku Buttonをクリックすると、「NancyOwinHeroku-sample」のデプロイが始まるため、動作確認を行います。
NancyOwinHeroku-sampleアプリ用のHerokuButton
HerokuButtonのコード
template
に自分のGitHubリポジトリを指定します。
<p><a href="https://heroku.com/deploy?template=https://github.com/thinkAmi-sandbox/NancyOwinHeroku-sample"> <img alt="Deploy" src="https://www.herokucdn.com/deploy/button.png"></a></p>
ソースコード
GitHubへとアップしておきました。
thinkAmi-sandbox/NancyOwinHeroku-sample
参考
OWINまわり
- One ASP.NET, OWIN & Katana
- OWIN - Open Web Interface for .NET とは何か? - しばやん雑記
- ASP.NET - Katana プロジェクトの概要