ASP.NET Core で CSV file を提供するソレを Azure App Service Web Apps と for Linux で動かしてみる

前回の続きです。折角作成したクロスプラットフォームの ASP.NET Core プロジェクトですし、相性抜群と私のなかで噂の Microsoft Azure App Service Web Apps の Windows 版と、新参者でかわいい顔のイケてるナイスパーソン 同 for Linux 版で、それぞれ動かしてみましょう。以前の記事が前提なのでレッツ・チェック・イット。

本記事は http://qiita.com/advent-calendar/2016/asp-net の5日目です。

いきなりの脱線

時代は広義の PaaS へ(サーバーレス含む)。というか、ホントにボタン一つで性能強化が出来るすよ。小さいシステムなのにリバプロメンテとか、open SSL のパッチ適用とか、煩雑な面倒見なくていいんですよ。ハード/OS壊れて泣かなくていいんですよ。

WordPress 立ち上げるのに、レンタルサーバーでハード借りたりOS借りたりするのダサイです。OS メンテし続けるの?壊れても?仕事減らしましょうよ。天下のグローバルプレイヤーに任せましょう。用途や規模、マネージしたい範囲にあわせて使える場所は、相当にあるはずです。

そんな私は最近発表された HPE の The Machine とか、Azure Stack とか、FaRM な SQL Server とか心待ちにしてます。

Windows な Azure App Web Apps で

本題。Web Apps を構築する手順は今回は書かないのです。これ読んでる方はご存じでしょうし。構成上はデフォルトのままで特に困る事なく動きます。さくっと作成して、VSからデプロイしてあげましょう。(どっかにあるから書かない、と言いながら、書いてあるウェブのドキュメントが古いことのほうが大半な時代になって、私はこういうの嫌いじゃないですが、大変ですね)

特に工夫もないです。普通に。
ここからしれっと。
こんなのり。

また脱線しますが、「.NET Core のASPNETCORE_ENVIROMENTDevelopment だとアプリのイニシャライズが slow だー」と stackoverflow で書かれていて、

http://stackoverflow.com/questions/39277386/asp-net-core-very-slow-first-page-load-time-with-development-environment-vari

Symbol サーバーオフれとかいろいろ書かれてます。私の別の環境だと、symbol サーバーオフは当然設定済みながらも、やっぱり遅くて。よくよく見てると、Razor View が30個40個ある場合の dotnet build -Debug が走るケース(構成が Debug )で RazorCompilation の初回が劇的に遅くなる傾向が見られていて、確認中。

これ、Release だと耐えられる早さ。で、クラウド側で Debug で配置すると、Disk I/O 故なんすかね、ARR がタイムアウトするぐりらいに遅くなってしまって、泣けます。いやねえ、デプロイ先だけど Debug にしたい事もありますよね。無いのかな。。原因がわかったらつぶやきます。

そろそろ Web Deploy 終わってるでしょう。確認しましょう。

click! click! click!

レッツ・ダウンロード・アンド・ファイルを開きましょう。ファイル名にOS詳細含めてますが、2012 R2 なんすね。

豆腐は SHIFT_JIS の証! on Azure

いい感じです。

で本記事の本題の一つ目。手元の Windows 10 環境での実行結果と比較しましょう。

on Windows 10

よくあるやつです。DateTime 型を処理系にまかせて変換してるので、日付のフォーマットが違うんですよね。Azure Web Apps のOS環境は、日本語圏を想定した環境がデフォルトではない。当たり前ですが。

前回のサンプルコードでバレバレですが、そういう事です。Azure Web Apps は日本語環境向けがデフォルトではないので、日付や時刻を表示する際、データを文字列として扱わなければならないとき、API で外接とやりとりする際、注意です。

UTCなノリで全て処理して、見せる場合に JST に変えるとかキメ必須です。歴史が長い DB の上にのっかる時には、文字列のフィールドに YYMMDD で入っていたりもするので、がんばれ SoR。

あと今回書かないですが、特に ASP.NET のローカライズとか意識せずに、EF Core 使ってDBアクセスしたりした場合に、LINQ で文字列を .indexOf() で確認したりする場合も、これ引っかかります。処理の前段階でスレッドのカルチャーを ja-JP にしてあげれば、そこそこ期待通りに動きます。

これ、.NET Core 1.1 で動かしてますが、1.0 のままでも動きます。RC2 だったかの頃は案外と苦労あったけど、今は対応が早いのでとても助かります。ナイス中の人ですね。これもね、自分でサーバー立ててたら大変ですよ。

Azure App Service on Linux Web Apps on Linux で

なんかこう、これのいい言い方ないんですかね。

まず入れ物作ります。これは手順を追いましょう。

検索すると出てくるので「作成」します

Windows 用のそれとは別の環境ということで、サービスプランも別になります。今のところ以下の地域でのみ作成が可能です。なんとなく近い場所を選びます。

コンテナーの構成を指定しましょう。

.NET Core v1.1 がない!無いので 「.NET Core v1.0」 を選びます。結論から言えばプロジェクトが 1.1 なので、これ動作しません。ですが、エラーメッセージの見方が参考になるので、あえてこのまま進みます。

いや、時代は進化しますね。 Linux で Web Apps みたいなの動いて、WordPress が動いてくれるなら(試してないですが)、こっちのほうがいいじゃん、って事多いんですよ。私は WordPress 嫌いですが。

ちなみに与太話してるのは、デプロイ待ってるからです。

今回のデプロイは VS から FTP で

時代的には Docker だろなんですが、詳しい人に教えてもらうまでは FTP です。Docker デプロイは凄い人たちを待ってます。温故知新。今回は VS からの FTP デプロイでやります。そこにこの記事の価値があるんです。

とにかく配置してみましょう。何故かここだけAzure Web App 初学者向け。

作成した App Service のプロパティを開くと、ここに FTP する際の情報が書かれています。

もし、他の Web Apps で FTP や Git でデプロイした事が無い場合には、最初に、デプロイ資格情報を設定する必要があります。

左のタブに「デプロイ資格情報」ってのがありますが、それです。そこで FTP する際のユーザー名とパスワードが指定出来ます。

実際に FTP する際、FTP/デプロイ ユーザー に表示されている “サイト名\ユーザー名” で入れてやる必要があるので、このあたりご注意です。

で、この設定を、VSに入れてみましょう。こんなノリで設定します。

なんでもいいですが、それらしく。
FTP の root は /home になるのですよ。

FTPS でいけます。「接続の検証」ボタンを押して、設定が間違ってないだろう事を確認しましょう。

サイトパスですが、 site/wwwroot を指定してあげてください。他にもあるんでしょうし、後で記載する「スタートアップファイル」の設定箇所で親パス見たりすれば動くのかもしれませんが、今回は動かす事優先。宛先 URL は空でいいです。ユーザー名はちゃんと入れてくださいな。

で、VSの出力を見て待ちます。これが結構、時間がかかる。ログ見てふーんと思いながらまちましょう。

先に言っておきますが、このデプロイでは動きません。動かないのでログを見に行くことになるのですが、そのためにあえて 1.1 でデプロイしてます。

けっこう長いので、トイレ行きましょう。トイレでスマホで記事漁っててもぜんぜんおけ。

先の準備として、Advanced Tools (kudu) を開いておきましょう。

アイコンが 十徳ナイフな K なんですよね。
Bash Bash
Ubuntu なんすね。

Bash 開くぐらいでは、大した時間もかからないので、時間が潰せません。FTP デプロイが終わるまで待ちます。ホント時間かかります。

まだまだ。

で、終了メッセージが VS 上に表示されたら、先に開いた Bash 使って、 tree あたりでファイルが配置されているか、確認してみましょう。

うむ、何か配置されている。よしよし。で次です。

Web Apps のタブに戻って、「アプリケーション設定」を選択すると、以下の画面になります。ビルドイン環境の設定をするのですが、ここに、以下のようにエントリポイントになる DLL を指定してあげます。

よくわかりませんが、プロジェクトの Main がある DLL でいいのだと思います。で、設定を保存します。

おもむろにサイトを開きます。

no response.

ちなみに、いくら待っても画面は応答しません。さぁログを探しましょう。

Bash on Ubuntu on Kudu で LogFiles の下を見てみます。dockerというディレクトリが作成されて、その配下に docker_~_err.logというファイルが出てるはずです。

この時点で Bash が動かずに死んでたら、遠慮無く上部メニューの「Debug console」からコンソールを開き直しましょう。(ファイルのデプロイでマウントし直すタイミング?で死んでるのかもしれません)

/home>cat LogFiles/docker/docker_108_err.log
2016-12-03T03:38:04.352190066Z The specified framework 'Microsoft.NETCore.App', version '1.1.0' was not found.
2016-12-03T03:38:04.352241965Z - Check application dependencies and target a framework version installed at:
2016-12-03T03:38:04.352250665Z /usr/share/dotnet/shared/Microsoft.NETCore.App
2016-12-03T03:38:04.352258065Z - The following versions are installed:
2016-12-03T03:38:04.352264565Z 1.0.1
2016-12-03T03:38:04.352270665Z - Alternatively, install the framework version '1.1.0'.
/home>

そうですね。そう書いてありましたもんね。失礼しました。

折角の検証なので、勢いレベルの手順で 1.1 から 1.0.1 へのダウングレードやります。VS に戻りましょう。

project.json を開いて、

  "dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},
...
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},

とだけ直して、あとはそのままにして保存。NuGet のパッケージ復元が始まります。本来は 他のモジュールも 1.0.1 にダウングレードすべきなんでしょう。よくわかりません。デプロイしかけて、ポケモンを数匹ゲットしに行ってください。

フォルダー wwwroot/lib/jquery-validation/dist を発行しています...
フォルダー wwwroot/lib/jquery-validation-unobtrusive を発行しています...
Web App は正常に発行されました ftps://waws-prod-sg1-019.ftp.azurewebsites.windows.net/site/wwwroot
========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========
========== 公開: 1 正常終了、0 失敗、0 スキップ ==========

おわったら、またもおもむろにサイトを開きます。ブラウザでURL入れてたたいてしばし待ちます。。

おお、きたよ!!

まぁまぁまてまて。まずログを見ようじゃないですか。

Kudu Remote Execution Console Type 'exit' to reset this console.
/home>cd LogFiles
/home/LogFiles>tree docker
docker
|-- docker_108_err.log
`-- docker_108_out.log
0 directories, 2 files
/home/LogFiles>
/home/LogFiles>cat docker/docker_108_out.log
2016-12-03T03:53:10.391341093Z Hosting environment: Production
2016-12-03T03:53:10.393067564Z Content root path: /home
2016-12-03T03:53:10.393710354Z Now listening on: http://*:5000
2016-12-03T03:53:10.393826952Z Application started. Press Ctrl+C to shut down.
2016-12-03T03:53:11.022073074Z info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
2016-12-03T03:53:11.022130673Z Request starting HTTP/1.1 HEAD http://127.0.0.1:38416/robots933456.txt
2016-12-03T03:53:11.792579847Z info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
2016-12-03T03:53:11.792635146Z Request starting HTTP/1.1 GET http://127.0.0.1:38416/robots933456.txt
2016-12-03T03:53:13.197478640Z info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]

それらしい感じでログ出てます。 GetCSV してみましょう。

おお。ファイル名はそうなったか。

ファイルを見てみましょ。

おおお。そうなったか。そうよね。そりゃそうだ。

LF の SHIFT_JIS 。ある意味で期待通りですが、日付のフォーマットはやはり違いますね。開発環境の Windows 10 日本語と Windows 版の Web Apps と Linux 版のそれとで DateTime の文字列表現は違いました。コード上は、当然だよな、的な感じです。

// CsvOutputFormatter.cs line.105 あたり
var _val = val.Value.ToString();

ありがちな話ではあります。いまどき、日付の処理を文字列操作でぐにぐにやる事はほぼないわけで、.NET Core を書くような人は困りはしないでしょう。1日後の日付計算で日付部分を数字にパースして足したり(死ぬやめて)するわけないのです。

が、まれにね。 外接先の SoR な API や DB の格納方式の設計が、時代を感じさせる感じになってたりして文字列操作をする機会は、あります。この類の事、面白くないわりに、常に考えないといけません。CSV を誰がどの処理系向けに使うのかっての推定が、実は最もめんどい話ではありますが、誰が使ってるのかわからんけど実装が必要だという人生の壁も事実ありますので、がんばりましょう。

デプロイのバリエーション

今回はデプロイを VS からの FTP にしましたが、GitHub からの配置もありますし、

PHP を FTP や GitHub 経由でデプロイしての CI なんかも、いけるはず。

いいですね。

積極的に OS のメンテナンスを放棄していきたいところです。コストに見合った運用ですよ。ホントに IaaS で作る必要あんの?というところで。

振り返ってみると、 ASP.NET の Advent Calendar なのに後半 Azure の使い方の話でしたけど、デプロイ先としてはセットみたいなものなので、多めに見てください。すいません。

今回のコードはこちらに。 https://github.com/arichika/AspNetCoreDeCsv

整理としては、

  • CSV が出てきたら、やっぱり身構えろ、そこに完璧はない
  • 日付とか処理系で変わる問題は永遠の課題っすな
  • Web Apps 最高。ASP.NET との相性抜群。

あたりですかしら。

GCP も興味ある @arichika がお送りしました。