NancyでHighchartsを使ってみようと思った時に、いろいろと悩んだことがあったので、メモとして残しておきます。
環境
- Windows7 x64
- .NET Framework 4.5
- Highcharts 4.0.4
- jQuery 2.1.3 *1
- NuGet
使うView Engineについて
NancyのView Engineは自分で選ぶことができます。NuGetにも複数登録されています。
View engines · NancyFx/Nancy Wiki · GitHub
最初はASP.NET MVCでも使われているRazor
を使おうとしましたが、SelfHostのせいかいくつかエラーが出て使えませんでした。Stackoverflowを見ると、過去には同様の例がありました*2。
- .net - Problems with Razor view engine in Self-hosted Nancy Console App - Stack Overflow
- c# - Unable to use NancyFx Razor ViewEngine - Stack Overflow
そのため、今回はNancyのデフォルトのViewEngineである、The Super Simple View Engine (以下SSVE
)を使うことにしました。
なお、SSVEにはインテリセンスはないようです。
c# - How to get Intellisense recognize SSVE? - Stack Overflow
Nancy + OWIN + SelfHostのプロジェクト作成
以前と同じく、コンソールアプリケーションのプロジェクトを作成し、上記のNuGetパッケージをインストールします。
次にProgram.csやStartup.csも作成しますが、ここも同様です。
C#でHighchartsを使う
Highchartsのライブラリとして、以前、Rubyのgemlazy_high_charts
を使ったことがありました。
C#でも同じようなライブラリがないかを探してみたところ、DotNet.Highcharts
というライブラリがありました。
DotNet.Highcharts - Home
良さそうなライブラリでしたが、HighchartsクラスがSystem.Web.IHtmlString
を継承していたため、Nancyで使おうとすると参照の追加が必要そうでした。
DotNet.Highcharts - Source Code
そのため、今回はHighchartsをそのまま使うことにしました。
Highchartsのダウンロード
公式よりダウンロードします(現時点の最新は、4.0.4)。
Highcharts - Download
なお、「DOWNLOAD BUILDER」で「Standalone framework」を選択するとjQuery無しでもいけそうでしたが、「EXPERIMENTAL」との記載があったので、今回は使いませんでした。
ダウンロード後は、path\to\project\Scripts
ディレクトリにhighcharts.js
ファイルのみをコピーしておきます。
JavaScriptファイルの用意
今回のHighchartsデータソースに対応するJavaScriptは、以前作成したPadrionoプロジェクトのJavaScriptを流用し、Highchartsと同じディレクトリに入れます。
JSONPでの書き方については以下を参考に、$.getJSON
を使いました*3。
JSONPで悩むある程度の人々へ - tsujimotter
また、JSONPを返すサーバーは上記のPadrionoプロジェクトを一部修正して、JSONPを返すようにしました。
How to create a JSONP cross-domain webservice with Sinatra and Ruby - ruby - json, jsonp, sinatra, jquery
Viewの用意
path\to\project\Views\
の下に作成します。今回はSSVEなので、以下の3ファイルを用意しました。
ファイル名 | 内容 |
---|---|
_master.sshtml | JSON,JSONPで共通する部分のView |
json.sshtml | JSON用の個別View |
jsonp.sshtml | JSONP用の個別View |
SSVEの書き方についてはNancy公式に記載がありますが、今回の使用内容をメモとして残しておきます。
The Super Simple View Engine · NancyFx/Nancy Wiki · GitHub
共通する部分のViewの作成
共通する部分のHTMLを作ります。
ただ、JSON用/JSONP用で使うJavaScriptが異なるため、それぞれのViewごとにscriptタグの指定を変える必要があります。今回は、@Section['<name>'];
を使いました(Razorの@sectionのようなもの)。
また、@Modelを使うことで、Nancyから渡したModelのプロパティの値を設定しています(Razorの@modelのようなもの)。
今回は、TitleやH1・現在時刻の表示で@Modelを使っています。
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>@Model.Title</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script src="../../Scripts/highcharts-4.0.4.js"></script> @Section['Scripts']; </head> <body> <div id='container'></div> <h1>@Model.H1</h1> <p>現在時刻 - @Model.CurrentDatetime</p> </body> </html>
個別Viewの作成
まず、@Master['<ファイル名>']
を使うことで、共通する部分をロードします。
次に、@Section['<セクション名>'] ~ @EndSection
を使って、scriptタグの記述を@Masterへと渡します。
@Master['_master.sshtml'] @Section['Scripts'] <script src="../../Scripts/json.js"></script> @EndSection
静的コンテンツの設定
ViewやJavaScriptが用意できたので、それらに必要な設定を行います。
Bootstrapperを使った、静的コンテンツディレクトリの追加
デフォルトでは、Nancyで静的コンテンツのディレクトリは path\to\project\Content
となります。
NancyFxチュートリアル「2. プロジェクトの細かい設定をする(+ モデルを作成する)」 - らびたろちゃんにっき
そこで、記事にあるようにBootstrapperを作成し、JavaScriptのあるディレクトリ(今回はpath\to\project\Scripts
)を静的コンテンツディレクトリとして追加します。
出力ディレクトリへのコピーを追加
ViewやJavaScriptのプロパティにおいて、デフォルトでは出力ディレクトリへのコピーが「なし」となっているため、アクセス時にエラーが発生します。
そのため、出力ディレクトリへのコピーを「常にコピーする」などへと変更します。
なお、StackOverflowのコメントとは異なりますが、手元では常にコピーするが必要そうでした。
How to serve static content in Nancy - Stack Overflow
Modelの用意
Viewの@Modelで使うためのクラスを用意します。
public class WebPageModel { public string Title { get; set; } public string H1 { get; set; } public string CurrentDatetime { get; set; } }
Moduleの用意
Viewを表示したり、JSONを返すようなModuleを用意します。
指定したViewを返す場合
View
を使います。また、Viewで使うModelのインスタンスを第二引数で渡すこともできます。
Get["/json"] = _ => { var webpage = new WebPageModel() { Title = "さつまいも編", H1 = "さつまいもグラフ", CurrentDatetime = DateTime.Now.ToString() }; return View["json", webpage]; };
JSONを返す場合
Response.AsJson
を使います。
Get["/api/json"] = _ => { var potato = new PotatoModel[] { new PotatoModel(){ Name = "紅はるか", Amount = 20, Color = "Pink"}, new PotatoModel(){ Name = "ベニアズマ", Amount = 10, Color = "DarkViolet"}, new PotatoModel(){ Name = "金時いも", Amount = 5, Color = "MistyRose"}, }; return Response.AsJson(potato); };
Response.AsJsonの場合、JSONPにも自動で対応しているようです。
Nancy を使って JSON API を実装するメリット - しばやん雑記
実行結果
ローカルとHeroku、どちらでも実行できました。
ソースコード
GitHubに上げました。
thinkAmi-sandbox/NancyHighcharts-sample · GitHub
Herokuボタンも置いておきます。