はじめてのASP.NET MVCでのお仕事、の感想とか

っというわけで、8月から何をやっていたかと言えば、ASP.NET MVCでWebのお仕事をしていました(・∀・)
リリースは来月なんですが、Ver.1の実装はもう終わってしまい、今はデザイン待ちということで、ここ数日は運用系の設計をメインにしていたり(´д`;)


っで、リリースもしてないシステムの話ということで、まだちょっと早いんですが、実際にお仕事でASP.NET MVCを使ってみた感想等について書いてみます。

システムソフトウエア構成

まず、作成したシステムの構成についてはこんなカンジです(・∀・)

OS Windows Server 2008
DB SQL Server 2008
Web ASP.NET MVC 1.0
ORM LINQ to SQL
ユーザ数 15,000 を想定

StackOverflow.comのアーキテクチャ記事っぽく書こうかと思ったけど、そもそもまだ稼働してないサイトなんで、ページビューとか書けないし簡単なソフトウエア構成だけ。
ソース管理がSubversionとかCIがHudsonだとかは今更なので省略(・ω・)

ソフトウエアアーキテクチャ

今回、ASP.NET MVCの実践投入がはじめてと言うのと、Web FormsはやっていてもMVC型のフレームワークにはさわっていない人や、MVC型のフレームワークはいつもやっているけど.NETは久しぶりというメンバも居るので、多少ベタになるところはあってもシンプルに作ろうという方針でいきました(・ω・)


まあ、やっていることはASP.NET MVCに限らずWebアプリでは一般的なプラクティスだったりするわけで、さほど特徴的なこともしていないんですが、以下、個別のトピックについて書いてみます。

レイヤとしてService層を用意

一般的に、使うテクノロジーによって、3層の各レイヤが薄くなったりすることもありますが。
とりあえず、ASP.NET MVCのVC層の他に、「処理」を記述するService層を用意して、データアクセスについてはLINQ to SQLという階層構成にしています(・ω・)
Controllerに書くのはヴァリデーションやService層の呼び出し、その結果をViewModel(Modelをそのまま使う場合もあり)にぶち込むと言ったグルーなコードだけで、「処理を書くの禁止」っという基本。


余談だけど、いい加減MVC(2)の解説をする際は、併せてBCEの話もきちんとするべきだよね(´д`;)
よく雑誌とかで、MVCフレームワークとは、みたいな入門記事が定期的に載るけどさ。
そういうのでBCE的な話をきちんとしないから、Controller/Actionにロジックを書くアホが後を絶たないんですよ、っとか言ってみる(#゚Д゚)


っで、基本はController-Service-LINQトランザクションスクリプトっぽい構成にしているんですが、一部だけドメインモデルっぽいものも存在していたり(´ω`)
単純なデータ処理についてはこの階層構造で処理するで良いんだけどさ、やっぱ多少複雑なロジックを扱うところについては、賢いモデルを作った方が自然な作りになるよね〜、っつって。


ちなみにDIは未使用です。
簡易サービスロケータみたいなものを作って、アプリケーション固有のControllerFactoryあたりで処理するような感じで間に合わせています(・ω・)

レイヤスーパータイプの用意

Controllerとか、アプリケーション固有のフックを入れる場所としてレイヤスーパータイプを用意。


当然だけど、共通の「処理」を記述するためのものではなく、共通の「振る舞い」を定義するためのもの(・ω・)
共通の「処理」はServiceなりUtilityに書くものだけど、これを勘違いしているケースもよく見るよね(#・∀・)

データアクセス

LINQ to SQLで楽チンぽん(・∀・)
っというか、今回ほとんどSQL書いてないですね。*1
LINQが生成する分で済んじゃったので、固有のSQLを書く必要があったのはフルテキストサーチの所くらい(・ω・)?


っで、色々書いているうちにグループ化の処理の記述にも慣れました(´д`)
GroupJoin()やSelectMany()が複数出てくると慣れないうちは戸惑うことも多いですが、SQLと対応づけて考えられるようになればどうということも無く。
ところで、LINQでCROSS APLYとかまで生成してくれんのね( ゚д゚)
まあ、結局その処理は使ってないんだけど。


ちなみに、参照系の全て処理についてはDataContext.Logの内容を出力して、そのSQLSQL Server Management Studio上にコピペして実行、実行プランの確認という事もきちんと行っています(`・ω・´)
そして、ああここには付加列があった方が良いねと気づく、っとか(´д`;)


あと、テストに当たっては大量のテストデータ(っと言っても、せいぜいユーザ15,000件とそれに紐付く数十万件のデータですが)が必要と言うことで、ランダムでそれっぽいばらつきを持ったテストデータを作成するプログラムも作っています(・∀・)


後は、データアクセスではなくモデルの話になりますが。
LINQで生成されたいくつかのモデルについては、導出項目的なプロパティや処理については、partialで処理を追加しています。
あと、ヴァリデーションについては独自のライブラリを使っているので、モデルのコードで定義するのではなくて、別途ルールを定義しています。

ルーティング

faviconのignoreとかを追加したくらいで、他はほとんど基本パターン{controller}/{action}/{id}で済んじゃいました(・ω・)
まあ、リソース指向を踏まえてURL設計したり、それと相性の良いDB設計をしているからだけど。
MVC系のフレームワークを使う時は、ちゃんとURL設計をすることは必須です(`・ω・´)
あと、リソースを特定するパラメータについてはルートで、更新用のデータについてはPOSTで、検索系のパラメータについてはGETでと、使い分けもちゃんとしています。

処理はPRGパターンが基本

基本。

ViewModelの使用

Controllerとビュー間のデータのやりとりについては、ViewModelクラスを用意しています(一部L2Sのモデルをそのまま利用している所あり)。
ViewDataの使用とかはまったく無しで、全て型付けしたViewPageを利用(・∀・)
あと、ViewModelクラス他は個別に名前空間をImportするのではなく、Web.configで指定。

マッピング

マッピングが必要なケースはほとんどなかったので、ライブラリとかは未使用です。
マッピングがあったのは、ViewModelから検索パラメータへの詰め替えが少しくらい(・ω・)?

Areaを使用

ユーザ機能と管理機能でAreaを分割。
っと言ってもASP.NET MVC 1.0なので、Area分けについてはS#arp ArchitectureにあるAreaViewEngineを使用しています。。


ちなみに、ユーザ機能はASP.NET MVCで、管理機能はWeb Formsでという考えもありますが(・ω・)
まあ、今回は管理といっても、サマリの参照みたいな機能がメインなので、管理機能もMVCで実装しました。

キャッシュの利用

参照系ページの一部はOutputCacheを使用しています。
ベンチを取ってみたら、キャッシュを使わなくても思ったより良い数字が出ていたり、DBを見てもそもそもデータサイズが最大数百MBくらいにしかならないので、キャッシュのヒット率とかもほぼ100%で推移してくれるているわけですが。
でも、ビューレベルでの出力キャッシュを使うと、他の細かいチューニングがどうでも良くなるほどパフォーマンスが良くなるわけで*2、静的コンテンツに近い参照系のページはキャッシュしています。

拡張メソッドの利用

HtmlHelper、UrlHelperについて、アプリケーション固有な拡張メソッドを用意しています。


っで、後で思ったんだけど、UI周りはもうちょっとPull MVC的なやりかたでやっても良い部分があったかも。
っというか、まだ時間的余裕はあるので、少し見直してみようかな(・ω・)?

ユーザコントロール

複数機能で同じ構成の画面要素については、ユーザコントロール化してHtmlHelper.RenderPartial()。
一部機能のaspxについては、中身がほぼRenderPartial()だけだったりして(´д`)

ヴァリデーション

ヴァリデーションはDataAnnotationsとかではなく、自前で用意したものを使用。
ヴァリデーションについてはこの前少し書いているので、そちらを参照。

認証

認証はMemberShipProviderではなくて、独自のMemberShipProviderみたいなものと、専用のFilterで対応。
認証っていうのは基本的に業務要件なので、標準の仕組みでは対応出来ないことも多いしね(´д`;)

その他の作成したMVC拡張

アプリケーション固有のControllerFactory、ViewEngineの他に、認証用のIAuthorizationFilterなんかを作っていますが。
その他のものとしては、form内の複数ボタンに対応するためのActionMethodSelectorAttribute派生だとかを作っていたり(・ω・)
後は、ActionResult派生としてCsvResultやXmlResultみたいなものを用意しました。

その他トピック

その他、今回のシステムでやっている特殊なこととしては、Flashとの通信やPDF出力なんかがあります。


Flashとの通信については、FlashからはHTTPServiceを使用して処理をリクエストする形で。
リクエストのパラメータについては、FlashからPOSTされた値をControllerでModelとして受け取り、レスポンスについては、オブジェクトをXmlSerializerでXMLに変換して返すXmlResultを用意してそれを利用しました。


.NETで通信というとWCFRest for ASP.NET MVCみたいなものもありますが、今回は単純にHTTP POSTとXMLによる応答で処理しました。
パフォーマンス的にもこれで十分でしたし(・ω・)

ASP.NET MVC自体への感想

後発な事もあって、MVC系のフレームワークとしてはわかりやすくて良い感じですよね(・∀・)
LL系のAfter Railsフレームワークとかと比べても。*3
拡張ポイントも十分だしね。


まあ、LL陣営から見ると、アプリケーションをさくっと作るにはコンポーネントが不足している感じかもしれませんが(・ω・)
個人的には、8割の要件にそのまま使えるコンポーネントよりも、多少コードを書いても適用範囲の広いライブラリの方が欲しいので、その辺りは特に文句は無いですが。


後は、ヴァリデーション周りはもっと強化されても良いかな〜、っというのは1つ。
もう1つは、ASP.NET MVC自体の話ではなくて、データアクセスの話になりますが。
Entity Framework的なやりかたがどうなのかな(´д`)〜っていうのと、LINQ to SQLの更新系を強化するような方向で、SQLを意識できる選択肢も残しておいて欲しいな〜というような所です。*4

今後の課題

締めとして、今後の課題について(´ω`)
まあ、色々と他のライブラリなんかも使っていきたいと思います(・∀・)


MVCContribとかも、もう少し活用したいし。
全部見てないから知らないだけで、使えそうなものが色々入っていたりもするし(゜д゜)


T4MVCについては、今回使わなかったんだけど(´д`;)
AreaViewEngineを使ってViewsフォルダが階層化していたり、ControllerやModelはWebとは別のプロジェクトにしていたりで、そのままだとうまく動かないところがあったので。

後は、今回はほぼ必要なかったけど、マッピングを多用するならAutoMapperとか。
全文検索ではLucene.netも気になるとか、試してみたいものはいくつかあるのです(`・ω・´)



ところで、また新しい.NETのお仕事の話があるわけですが。*5
1,000台くらいの機器と通信するサーバアプリと、そのユーザインタフェースとなるWebシステムみたいな構成で。
まあ、内容的には、こっちはMVCではなくWeb Formsで行くってところかな(・ω・)
サーバアプリの方は、キュー制御、スレッド制御、通信とかが絡んでくるので、自分がメインでやるんだろうけど。

*1:L2S用の独自Extensionなんかも使っていますが(・∀・)

*2:別に細かいチューニングを軽視してるわけじゃないよ(´д`;)

*3:JavaでもStrutsにAfter Railsな皮を被せたりするけど、本当は0から作ったASP.NET MVCと同じようなもの用意したいところ(´д`;)

*4:UpdateBatch、DeleteBatch的なものが標準であれば満足なんだけど(・ω・)

*5:Compact Frameworkのお仕事ではなく別のお話。っというか、CFのお仕事も進めておかないといけないんだけど…(´д`;)