MVCをつかったCMS。バージョンが0.8でずいぶん進んでるのに今まで全然知らなかったです。機能的にはほぼ互角な感じだけど、動かすと最初にウィザード形式で設定する分、使う人にとってはすこしとっつきやすいかも。Writerとかの外部エディタに任せるスタイル。これはコレでいい割り切りだと思うな。プロバイダサービスみたいに沢山の人にたいして、使ってもらうんじゃなくて会社のサイトや個人のサイトをターゲットプラットフォームとして考えた場合、妥当な選択。編集機能にリソースをさくより、API実装に専念しておけばいいよね。初期のデータプロバイダがDBじゃなくてファイルベースのXMLだったりする。SQLのプロバイダもあって、テーブル構築用のSQLも用意されてます。コードを追っかけるとRepositoryを直接インスタンス化してる箇所がWebMvcプロジェクト(Webアプリ)にもあるから、ファイルストレージを前提として開発してるんだろうね。開発チーム内で分業されてるからかな?ファイルストレージで気になるのはファイルフォーマット。いう形式でファイルに保持してるのかなと思ってみてみたら、Atom形式のXml。Atom関係のモデルクラスはDomainプロジェクトに集約されてて、そのモデルを使うので、DBのモデルを直接使うなんて事はしてないんですな。APIをとことん使いこなす設計ですばらしい。ファイルだからIO負荷が気になるところだけど、そこはシンプルにRepository実装内で、staticなDictionaryを持ってて、そこで保持。ファイルが書き換わったときにDictionary内のデータを破棄するために、ちょっとオシャレな作り方してて参考になるので、ここで引用。RepositoryプロジェクトのFile/XmlCache.csの最後の所。}実体をキャッシュに入れちゃえばいいじゃんと思うけど、なんかあるのかな。別のライブラリでSgmlReaderっていうのも使ってる。それぞれ用途が違うのかな。どっちかだけでいいって物でもないの?整形するのとパースするのとで使い分けてるのかな。ThemeViewEngineを使ってる。いっても、View/MasterPartialViewそれぞれのLocationFormatをセットして、Find系を実装するのみ。フォルダ構成のなかにViewがなくて、themesっていうのがあるけど、そこにすべてのViewPageが入ってます。LocationFormatに登録されてるから問題なし。XMLとサムネイル画像が入ってるくらい。URIで各ページの拡張子にフォーマット指定でxhtmlってつけるのをルールにしてるのは、RESTfulを意識してるからなのかな。ソースをダウンロードして、動かそうとするといきなりコンパイルエラーがでるのはご愛敬。単純に文字列閉じてないだけ。行50の部分を↓変更。デフォルトのtrailerがなんなのかオンラインでソースを確認しても化けててわかんないので、とりあえずなんか入れとくってことで"..."を使う。※trailerは文字列を指定の長さに切り抜いて、元文字列が指定長以上なら後ろにくっつける文字列。APIを公開するのにあわせて、Atom実装のコードがたくさんあるけど、その他はパッと見シンプルな実装な感じ。ViewPageも型指定(強い型付け)でViewDataを扱ってるし、コードをほとんど含まないように書かれててOxiteよりも綺麗な印象。好みの問題?ちょっとOxiteのコードは量が多くて、冗長な感じがしなくもないし...。SQLのみなんだけど、テストしやすくしたいし、DataContextクラスに大量のコードを書くのもいかがな物かと。Repositoryパターンだよね!ってことで今更ながらコードを書いてみた次第なんです。SQLのモデルクラスをそのまま使うってことで勘弁してもらいます。クラスの変換とか余計な処理も必要になるしな~、と。SQLを使って実装するんだけど、SubmitChangesってどこに書くのがいいんだか、ちょっと悩ましいところだったりしまして。データモデルを分けて定義しておけば、サービス層からデータアクセス層にデータクラスを渡して、その中でL2Sモデルに値をマッピングするのが王道パターンだとしても、それをやりたくない場合、サービス層でL2Sモデルに直接値を入れたりすることになるじゃないですか。わかりにくい説明でなんだかわかんなくなるな。{get;set;}}っていうのがあったとしましょうよ(これがdbmlから自動生成されたとしてください)。そのDataContextクラスをTestDataContextとしましょう。Person(){Id=1,FirstName="ロビン",LastName="ニコ"};db.People.InsertOnSubmit(person);db.SubmitChanges();なんて書きますよね。←これで削除確定みたいな。model);}とか、って書きたくなるけど、Updateは実質SubmitChangesだけじゃん!みたいな。この例だと引数は最大3個でいいかもしれないけど、クラス次第でスゴイ引数の数になっちゃうから、もう一つ上で直接モデルに値を入れるほうがコード少なくて済むって話しです。普通にRepositoryの関数内で都度SubmitChangesを呼び出すのが正しい実装、だと思う。Site↑ここでもそういう書き方にリファクタリングしてるし。すると、複数の更新をまとめてSbumitChangesしたい、なんてのはダメにするか、そういう関数をRepositoryに追加するってことになる。データ操作の確定のためのSubmitChangesもサービス層で呼べばいいのかっていうと、単純にDataContextを上の層で持ちたくない(db.SubmitChanges()なんてコードをサービス層で書きたくない)。結局、単純にSubmitChangesと同名のメソッドをRepositoryに実装して、それをサービス層で呼び出せばいいのかな?と。したらDataContextをサービス層が弄る必要ないし。encyclopedia)。データ操作の戻り値として、IRepositoryを返せば(この場合ならIPeopleRepository)つなげられるな~、と。SubmitChanges();}↑インターフェースはこう替える。実装は済んでるとして、呼び出し側では↓こう書く。.SubmitChanges();これなら間に、Deleteとかも連結出来るもんね。他のRepositoryをどうするんだよ、って言うのは、まぁ...、そうなんだけど...。同じRepositoryの場合はコレでいいですかね(結局L2Sモデルクラスをサービス層で使うんなら分離出来てないじゃないか、っていうのはその通りなんだけど...)。開発2008年12月22日月曜日Oxiteのソリューション構成ちょいちょいソースを見ていこうと思うところで、まずはソリューションの構成を確認して、どんなコードがどのプロジェクトに含まれてるのかを把握しとこうかなと。ソリューションを開いたところで、表示されるプロジェクトは↓。それぞれのプロジェクトに何が含まれてるのかを見てみたよ。1.OxiteこのプロジェクトにOxiteで共通のライブラリコードや、インターフェースが集中。BackgroundServicesにBackgroundServicesで実装する各種バックグラウンドタスクのベースクラスや、インターフェース。Configurationにはweb.configのカスタムエレメント用のクラス。クラス自体は大量にあるけど、内容は各設定値を取得するための物だからエレメントの数だけクラスがある感じ。Dataにはデータベースのモデルクラスのインターフェース。実装はLinqToSqlProviderに入ってる。HandlersにMetaWeblogAPIとXmlRPCのクラス。コントローラクラスだけじゃなくてこのハンドラもルーティング登録されてるからコントローラを探しても見つからず。Routingにはそのままルーティングを登録するクラス。ルート登録の詳細がMVCのWebアプリケーションのglobal.asaxじゃなくて、ここにすべてまとめて入ってる。Searchに検索機能のインターフェース。あと、ルートに共通関数が入ってる。StringExtensionsクラスにStringクラスの拡張メソッドが入ってるんだけど、なんとこの中でAntiXssLibraryをラップしてる関数有り。AntiXss.HtmlEncodeとAntiXss.HtmlAttributeEncodeを使って、エンコードするようにしてる。バージョンは先日公開された3.0じゃなくて1.5を使ってる。古いのを使ってるのが気になるところだけどリリースの関係でOxiteの先にリリースしてるし、MIXのサイトでも使ってるって事で、そこはやむなしな感じで。2.Oxite.BackgroundServicesバックグラウンドで動作する機能の実装。POST)の2つを処理してる(と思う)。CreateMessagesFromSubscriptions(BackgroundService)コメントをメールメッセージとしてMessageRepositoryに登録。SendMessages(BackgroundService)MessageRepositoryに登録されてるメッセージをメール送信。CreateTrackbacks(PostBackgroundServiceAction)トラックバック要求をBackgroundServiceActionRepositoryに登録。SendTrackbacks(PostBackgroundServiceAction)BackgroundServiceActionRepositoryに登録されてる要求を実行。3.Oxite.LinqToSqlProviderQxiteプロジェクトのData内に定義されてる、リポジトリの実装。SQL(dbml)で定義されてるのをそのまま。あとIQueryable<T>の拡張メソッドでページングデータ(PageOfAList<T>)を取得するものや、モデルクラスの拡張機能など。MembershipRepositoryがoxite_User/oxite_Roleなんかを見るような独自実装なのがちょっと以外。これはGravator対応とかが関係してるんだろうか?関係なさそうだけどなんでASP.NETのMembershipじゃダメなんだろうね~。Searchで実行するための実装。http://soap.search.live.com/webservices.asmx?wsdlへのWeb参照(SOAP)で検索要求を送信して、結果を取得するようになってる~。Post.SearchPost(TitleとBodyをくっつけたもの)に対してContainsで単純に検索してる。6.Oxite.MVCこのプロジェクトに全部のコントローラクラスが入ってる。クラスがHttpApplicationを派生したクラスとして、定義されててこの中のOnStartでバックグラウンドサービスの開始や、ルーティング登録の実行。BeginRequestでリダイレクトがどうのこうのって処理があるけど、なんのタメの機能なのかよくわかんないかも。ControllerもBaseControllerっていうクラスをベースにして実装。ルーティングとコントローラのクラス名を見比べると、URLの設計はそれはそれだろ的な思いもちらほらと。AccountController(Users/{userName}/~,SignIn,SignOut)AdminController(Admin/~)ArchiveController(Archive/{*archiveData})AreaController({areaName}/~)FileControllerHomeControllerPageController({*pagePath})PingbackController({id}/Pingback)SearchController(OpenSearch.xml,Search/~)SEOController(Robots.txt,SiteMap/~)TagController(Tags/{tagName}/~)TrackbackController({id}/Trackback)Viewで使うViewPageクラスの代わりにBaseViewPage/BaseViewUserControlなんかを定義。OxiteSite(Webアプリケーション)で使う共通関数なんかもここで定義。Oxiteでも共通関数があったりするけど、Webアプリケーションでしか使わないのはたぶんここに集中してるんだろね。ヘルパーの拡張なんかもここ。FeedResultっていうのがなぜかViewResultから派生させて、Viewとして定義してるのはちょっとダサイ気がしなくもない。Trackback/Pingbackを属性クラスで定義して、ViewDataにディスカバリー情報を入れるっていうのはカッコイイ。7.OxiteSiteこれがサイトの実体プロジェクト。実質コントローラもロジックも別のプロジェクトにごっそり入ってて、ここではもっぱらViewに関する物だけがある。Global.asaxのコードビハインドではOxiteApplicationクラスから派生。ほとんどのViewにAtom/Rssそれぞれのフィード専用Viewが入ってて冗長な気が...。綺麗にできるんじゃないのかな~。特徴的なのはViewDataがすべてDictionaryのままで、View内キャストするようになってるとこ。ViewPage<T>なんて定義はなく、すべてキャスト。Viewに結構なコードが含まれてる気がする。あって、MetaWeblogAPIに関する設定が書かれてた。こんなファイルがあるのを初めて知りました。含まれてるプロジェクトはこんな感じってことで。中身・機能についてもちょいちょい見ていきます。MVCの次のリリースが1月にRCを出すってところ。IDataErrorInfoっていうのが、どういうインターフェースなのか気になって年越しが落ち着かないじゃないですか!View生成の時にScaffold出来るとかは、正直あんまり興味なかったりするけど、管理機能を作るのがどれだけ簡単かが、重要なエンタープライズ(社内システム)開発には有効なんだろうね。Viewのコードビハインドが全く生成されなくなるっていうのはすばらしいかも。して、そうすることで、コンパイルしなくてもViewData.Modelにアクセス出来るようになったりするんだろうか。試してみたら、今のバージョン(ベータ)でも上記サイトのようにInherits="System.Web.Mvc.ViewPage`1[[モデルクラス名,アセンブリ名]]"を書いておけば、コンパイル無しでもViewData.Modelにアクセスできるね(`1ってついたクラスしてだったり面倒だけど、ジェネリックバージョンはこっちなんだもんな~)。ViewData.ModelじゃなくてModelから書けるようにもなるっていう。すっごく気になるのがJavaScriptResult。いう風に使えるんだろ。JavaScript内でViewDataを参照したいときとか、単純に外部jsに出来ないから、aspxにしてるけど、それをscriptタグで読み込むような使い方にしちゃうと、コードの色分けもIntelliSenceも効かなくてちょっと切ない。JavaScript埋め込みたくないし。JavaScriptResult関係ない気がしてきた...。1月にRCだと、その次はいつになるやらデス。Homeいろんなニュースサイトでも取り上げられてるから知ってる人も多いと思います。MVCで作られてるってことで楽しそうじゃないですか。Online↑ここで紹介ビデオが見れます。何にせよ、どんなものかを知るには動かしてみるのが一番。いうことで、まずはソースのダウンロード。ファイルを解凍してソリューション(Oxite.sln)を開いて見よう。あれれ~?怒られちゃった。dbprojが開けないってさ。そんな人のタメにもう一つソリューションファイル(Oxite.VWDExpress.sln)が入っててそっちを開きましょう。データベース関連のプロジェクトはたぶん使う事ないし。今度は問題なく開けたので早速実行。使い方がサッパリ分からない。ログインしてみるものの(Admin/pa$$w0rdで)「で?」って感じです。Page"がページの投稿みたいだけど、画像ファイルをアップロードするインターフェースもWYSIWYGなエディタがあるわけでもない。Writeがピッタリなんじゃん?と、Aboutページにも書いてるしで、早速インストール(使ったことないも~ん)。アカウントの設定をして、いざ投稿!なるほど。