2009年8月4日火曜日

LIFE

歌ネットはいつからログインしなくても良くなったんだろう。

キマグレン LIFE [無料]歌詞検索の歌ネット

今朝、この歌の歌詞を口ずさまずにはいられなかったのは、昨日のめざましライブがキマグレンだったからなわけじゃない。

IMG_2501

泣きたくて、笑いたくて...。

いや、まじ、もうメガネかけたまま寝るのはやめようよ。学習しようよ。

話変わって、土曜日、恒例の港南区子供会主催(港南区関係無いのに呼ばれるのはナゼなんだ...)のアイススケートイベントのお手伝い。朝8時から3コマ使って15:30まで氷に乗りっぱなしでした。子供達相手に一緒にスケート滑ったり教えたりするんだけど、ずっと中腰で疲れたっす。でも、ちょこっとホッケーして見せたりして楽しかったよ!

IMG_2495

朝一はすっからかん。

IMG_2497

ちょこっとホッケー体験コーナーもあり。

IMG_2498

全3枠で756人だって。多いよ...。次回は来年2月6日だそうで。もうリンクの予約は入れてるからスケジュール空けといてだってさ。がんばる...。

2009年8月2日日曜日

MVC V2のチラ見

やっと、ため込んだFeedの処理に追いついて、ビデオの確認ができた。

Hanselminutes on 9 - ASP.NET MVC 2 Preview 1 with Phil Haack and Virtual Scott | Scott Hanselman | Channel 9

内容も15分と短いので、是非。

ってことで、このビデオ見つつ少しだけv2のソースも少しだけ確認。Editor/EditorFor(EditorTemplateフォルダ)、Display/DisplayFor(DisplayTemplateフォルダ)がそれぞれあって、なおかつLabelForがFuturesから標準に入ってきてる。ここでTextBoxForを作ろうとして、これは拡張性に問題がありそうだと気がついて、Dynamic Dataで使われてるTemplateベースのレンダリングを参考に拡張方法を変えたのかな。前のFuturesには入ってたモンね、 TextBoxFor。

なので、TemplateHelperがかなり重要なポジションをしめる気がする。さらにModelBinderの時と同じようにDefaultDisplayTemplate/DefaultEditorTemplateを用意して、ある程度は自動テンプレート出力をしてくれる模様。すばらしい。

v2 のリリースノートをチラ見した時には「えぇ~、そっちかよ~!」と思ったけど、中身を見ると素敵かも。ITemplateでのテンプレート処理じゃなくてあくまで、HTMLをベースにascxでのテンプレート処理にこだわることで、ViewStateを取り込まないし、クリーンHTMLをはき出せるしで、 MVCらしさをそのまま引き継いだ上での拡張っす!System.Web.UI.WebControls.DataBoundControlModeがInitializeDataCellDataControlRowStateを使わなくて良くしてくれてるんでしょう。

Scott Hanselman's Computer Zen - Hanselminutes on 9 - ASP.NET MVC 2 Preview 1 Released

↑ここにも書かれてる通り、Preview1ではそれほど大量の機能追加はなくて、Preview2が本気リリースっぽい。なので、V2に関しても順を追って追いかけて行くことで、一度に沢山の機能を調べなくて済む感じです。

DataAnnotationsの取り込みがどの程度のものなのか。その片鱗をこのビデオで垣間見れた気がします。Dynamic Dataと同じくらい取り込もうとしてますね。DataType、DisypayNameにUIHint、それらもしっかりとUIの出力(TemplateHelperとDefaultEditorTemplate)に反映されてる。前まではDataAnnotaionModelBinderを使って、システムに対して入力方向での連携で入力値検証でしか利用してなかったのが、V2からは出力方向にもしっかり活用。なので、Templateベースの出力になってるのもうなずける。

大枠はいつものごとく、ガスリーさんところで書かれてるから、そこで確認。

ASP.NET MVC V2 Preview 1 Released - ScottGu's Blog

まだちゃんと見てないけどね!

すでにフィルさんところでAreaに関する投稿(Single Project Areas With ASP.NET MVC 2 Preview 1)もあるし、Maartenさんとこ(ASP.NET MVC 2 Preview 1 released!)にも簡単な説明が出てるので、これから少しずつ見ていこうと思います。

つか、この週末でちゃんと調べる予定だったのに、全然観れなくてちょっと残念...。

T4MVC再び

世界中でMVC v2祭りな雰囲気の中、少し前にリリースのあったT4MVC 2.4.0.1について。早くMVC祭りに参加したいところだけど、そこは焦らずに少しずつ...。

Angle Bracket Percent : T4MVC 2.4 updates: settings file, sub view folders, ActionName support and more

前回のT4MVCの投稿でActionNameをサポートするようttファイルの書き換えを行ったけど、新しいバージョンではしっかりとその辺も含めた改良が施されてます。なので、もうActionNameで名前を変えたものを指定したいからと、たけはらエディションを使う必要は全く無くなりました。

どうやってActionName属性を取り出すのかなと確認したところ、メソッドのCodeAttribute2を取り出してActionNameAttributeが付いてるかを見てました。ActionMethodInfoが変更かかってるのも合わせて、やり方はだいたい同じですね。間違ってなくてホッとした。変更前のAction名が選択肢に出てくるあたりの仕様も同じだし。

HomeControllerに以下のIndexPostを追加してみる。

    public virtual ActionResult Index()
    {
      ViewData["Message"] = "Welcome to ASP.NET MVC!";

      return View();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [ActionName("Index")]
    public virtual ActionResult IndexPost(string value)
    {
      ViewData["Message"] = "Welcome to ASP.NET MVC!";

      return View();
    }

このIndexPostを参照するようにIndex.aspxにFORMを書いてみる。

    <% using (Html.BeginForm(MVC.Home.Actions.IndexPost, MVC.Home.Name))
       { %>
       
       <input type="submit" value="送信" />
       
    <% } %>

結果、出力されるHTMLは↓。

    <form action="/" method="post">
       
       <input type="submit" value="送信" />
       
    </form>

それから、既定ではMVCがクラス名だったり、ViewsフォルダやControllersが固定だったけど、今回からT4MVC.settings.t4というファイルで変更出来るようになってます。なので、MVC.Home.~じゃ無くてMy.Home.~とかに変更も可能。サブディレクトリを再帰(なんちゃらRecursive関数達)で潜っていくようになってるので、より実用的に。

Actionの引数をなくしたoverloadを定義してるみたで、上記BeginFormの書き方を以下のように変えてもOKらしい。

    <% using (Html.BeginForm(MVC.Home.IndexPost()))
       { %>
       
       <input type="submit" value="送信" />
       
    <% } %>

だけど、これで出力されるURLがなんかキモイ。

    <form action="/?RouteValues=System.Web.Routing.RouteValueDictionary" method="post">
       
       <input type="submit" value="送信" />
       
    </form>

変なの。と、思って出力されたコードを確認してみたけど、今回のような使い方の場合、上記のようにBegineFormを使うと、標準のHtmlHelper.BeginFormが呼ばれるから変なURLになる。正しくは↓こう。

    <% using (Html.BeginForm(MVC.Home.IndexPost(), FormMethod.Post))
       { %>
       
       <input type="submit" value="送信" />
       
    <% } %>

ちゃんと、FormMethodを指定しましょう。じゃないと、T4MVCで定義してるBeginFormのoverloadに入ってこないもん。こうすれば、ちゃんとURLが出てくるようになりました。にゃろめ。ちなみにルーティング登録時(MapRoute)でもマジックストリングを使わずに登録できるようになってるT4MVC。

最高です。

2009年7月26日日曜日

楽しみ

昨日、今期MHLのプレーオフ初戦でした。見事初戦敗退...。なんか、切ないけど、まぁ、しょうがないか。練習も出来てないし。個人的にそうは思ってても、チームメイトはどう思ってるのかな~。

そんなこんなで、アッサリと夏も終わり(球児じゃないけど)、後はのんびりとホッケーして次期シーズンに備えるだけなわけですが、なにやら次期はエントリーチーム数が多すぎるみたいで抽選らしい。抽選に落ちたら全く試合に出れなくなっちゃうね~。どうなることやら。今更他のチームで出たいとも思わないしな~。抽選落ちしないことを祈るのみ。な~む~。

試合が午前中で終了したから、午後戸塚に一汗かきに移動。スズキ君も来て久しぶりにシャキッとしたホッケーもできて面白かったよ。でも、あれだよね、マッチョな感じが楽しい時間をダメにするっていうのもあるよね。ピックアップっていうと、その時にいる人それぞれ全然違うポイントを楽しいと感じるわけで。上達することだけを目的にするのもいいし、単純にそこにいるメンツでホッケーするのが楽しいからっていう理由だけでプレーする自分みたいな人もいるし。サヨちゃんとの対戦だけを楽しんだりするのも楽しみ方だと思うわけですよ。マッチョもいいと思うけど、それをみんなの共通の目標とか楽しみだっていう価値観はとても狭い世界でしか物を見れなくなりかねないぜ?

なんてね。

2009年7月18日土曜日

あちゃ~!おちゃ~!

いや~、2週間沈黙だったっす。なんか先週もちゃんとエントリ書いたんだけど、書いた後に恐ろしい勘違いエントリだと気がついて即削除。読まれたらちょっと恥ずかしい内容だったんで、修正とかじゃなく削除しちゃいました。ルーティングとURL引数(QueryString)を超勘違いしてた。とりあえずURL引数に禁止文字を使いたい場合は[FIX] .NET Framework 1.1 で "HTTP 400 - 正しくない要求" エラー メッセージが表示されるで無理矢理できるってことで(Routingには関係無い話でした)。

こないだ大事件が起きて。やっぱりキーボード(パソコンの)はこだわりの逸品を使いたいじゃないですか。普段からノートPC使ってるとデスクトップのキーの深さに疲れちゃうから、お気に入りは薄いキーボードなんですよね。押すのも楽だし。ぬたーん、とした感じがいいじゃないですか。

なもんで、使ってるのは電源メーカーで有名なENERMAXのアルミ削りだしキーボード(KB007U-B/KB007U-S)なのね。ひんやり感がたまらない。ThinkPadのパームレストが熱いのとは雲泥の差。

kb007ub-b06

「今週会社がつぶれます」のエントリは書いてないけど、そんな感じで新しい会社に移ったて、そこでももちろんこのお気に入りキーボードを使うデスよ。マウスもお気に入り使うデスよ。べーさんなんかごつい体型なのにキーボードは弁当箱か!ってくらい小さいデスよ。

いつものように解決方法が思いつかない~と、もんどり打ってたらコップを倒した...。これがまた奇跡のような倒れしてキーボードの上にこてーんと。なぜ、キーボードに向かって倒れたんだ...。もちろんコップの中身が全部キーボードに注ぎ込まれるじゃないですか。泣ける。もう帰ろうかと思ったけど、まだ14時...、みたいな。こぼしたのはお茶だったから慌てて拭いてキーボードを外に干した。とりあえず、乾いたところでつなげてみたらなんとなく普通に使えてホッとしたけど。あれだよね、コップは気をつけないとね!そういえば、前にもコーヒーをこぼした気がする...。コーヒーとお茶にまみれてもがんばって動くキーボードにはこれからも耐え続けてもらいたい。

ちなみにドラクエも全然進まない。この連休は旅にでるぞ~!

2009年7月4日土曜日

男らしさってなんですか?

前回のエントリーに引き続きT4MVCです。

前回判明したのが、ActionName属性を指定したアクションはオリジナルのアクション名でしかMVCクラスに展開されないというもの。で、改善リリースを待つか、自分でttファイルをいじるのか、どっちが男らしいかというところで、とりあえず逃げの一手を打ったんでしたね。

このままじゃべーさんにどやされる。週明けに「この腰抜けが!」なんて言われた日には、枕を涙でぬらす日々。涙じゃない、悲しみのシミだよ、なんて言ったところで「誠意ってなにかね? by 文太」とたたみかけられる。

まぁ、いいや。

早速、面白そうなものを見つけたんだから、T4追いかけてみるかと、VSでソースを開くと真っ白背景に白の文字。あ、コードハイライト効かないんだった。

そんなときには"Clarius Visual T4"。Professionalエディションを$99.99払ってまでは使い込まないだろうから、Communityエディションで。無料だし。Code Generatorエディション出たら買ってもいいかもね。いや、買わないか。で、インストールして早速T4MVC.ttファイルを開いてみると...。

t4mvc1

ぽかーんデス。なんじゃこれ。テーマ設定してるとグチャグチャっすね。

Clarius Forums • View topic - t4Editor and custom fonts and colors

フォーラム見てみたら、白バックのデフォルトテーマに戻せと書いてるけど、日本語版のVSだからか、「ツール>オプション>環境>フォントおよび色>テキストエディタ・表示項目」にそんな選択肢がそもそも出てこなかったり。ガッカリだな。無料だし、それもやむなし。そういえば、CommunityエディションだとIntelliSenceも使えないんだった。インストールする意味がまるでなかった。

で、結局↓こんな素っ気ない画面で。

t4mvc2

そろそろ、中身を確認せねば。T4の使い方は前にどこかで読んだことがあったから、細かい仕様的なのは無視。とにかく、<# #>で囲まれてる部分がテンプレート処理部。で、テンプレート内で参照出来る変数を下の方で宣言してて、その辺にいろいろコードがあるはずなので、そこら辺中心にチェックで。

一応ASP.NET MVCに関する投稿デス。

たぶんアセンブリ内をリフレクションでグルグル処理してるんだろーなと、たかをくくってたらこれが全然違うのね。ビックリした。CodeFunction2って誰ちゃん?CodeElementインターフェースってどこからはえてきたの?みたいな。どうやらVisual Studioオートメーションってことらしい。クラスの定義をpartialにしたり、関数定義をvirtualにしたり、ソースをいじるのにそうしとかないと面倒なことになるからなんだろうね。そんな物の存在を全然知らなくてたまげたけど、使う部分はちょびっとだけなんだから気にせず読み進める。

Controllers変数の中にControllerInfoのコレクションが入ってて、ControllerInfo.ActionMethodsの中にActionMethodInfoのコレクションが入ってるんだって。それらコレクション達を見ながらコード部を生成させる仕組み。今回はActionNameAttributeが宣言されてれば、アクション名をそっちに切り替えるってことをしたいので、ActionMethodInfoあたりを中心にチェック。ふと思ったけど、オリジナルのアクション名が消えるとちょっと分かりにくいかも?オリジナル+ActionName指定の両方を展開しといたほうが、優しさチラリな気がしたので、そういう事にします。

CodeFunctionのNameを書き換えるのは無理なんだろうから、ActionNameが指定されてるならそっちの名前を返すように内部のクラスを書き換える。

// Data structure to collect data about a method
class FunctionInfo: BaseFunctionInfo {
public string _actionName = null; public FunctionInfo(CodeFunction2 method) : base(method) { } public FunctionInfo(CodeFunction2 method, string actionName) : base(method) { _actionName = actionName; } public string Name { get { return _actionName ?? _method.Name; } } public string ReturnType { get { return _method.Type.CodeType.Name; } } public bool IsPublic { get { return _method.Access == vsCMAccess.vsCMAccessPublic; } } }

太字の部分が追加したコードです。さらに、このクラスを派生させてる部分も同じように変える。

// Data structure to collect data about an action method
class ActionMethodInfo: FunctionInfo {
    private bool _isOverride = true;
	
    public ActionMethodInfo(CodeFunction2 method, ControllerInfo controller): base(method) {
        Controller = controller;
    }

    public ActionMethodInfo(CodeFunction2 method, ControllerInfo controller, string actionName): base(method,actionName) {
        Controller = controller;
        _isOverride = false;
    }
    
    public bool IsOverride {get {return _isOverride;} }
    public ControllerInfo Controller { get; private set; }

    public string GeneratedName {
        get {
            // If the action name would cause a class/method conflict, append an underscore to it
            if (Controller.Name == Name)
                return Name + "_";
            return Name;
        }
    }
}

これも太字。IsOverrideって言うのが追加されてるのは、Controllerの書き換えをされる時に、アクション関数はすべてvirtualになって、そのControllerを内部で派生させて、すべてのアクションをoverrideしてるから。でも、今回追加するActionNameで指定したアクション関数はそもそもそんな名前でControllerには存在しないから、派生クラスでしか不要だし、overrideするものじゃ無いじゃないですか。なので、ここでそのフラグを保持しておいて、テンプレート処理部でこれを見て、overrideを付加するかどうか判定させるって感じです。

続いて、ActionMethodsコレクションを構築しているProcessControllerActionMethodsを書き換える。

void ProcessControllerActionMethods(ControllerInfo controllerInfo, CodeClass2 type) {
    foreach (CodeFunction2 method in GetMethods(type)) {
        ~ 長いのでココはカット ~
        // Collect misc info about the action method and add it to the collection
        controllerInfo.ActionMethods.Add(new ActionMethodInfo(method, controllerInfo));

        // ActionNameAttributeを見てそっちも追加する。
        // オリジナルが不要なら↑のAddを削除。
        foreach(CodeAttribute2 attr in method.Attributes)
        {
          if(attr.Name == "ActionName")
          {
            foreach(CodeAttributeArgument arg in attr.Arguments)
            {
              var actionName = arg.Value.Replace("\"","");
              controllerInfo.ActionMethods.Add(new ActionMethodInfo(method, controllerInfo, actionName));
            }
          }
        }
    }
}

太字部です。なんか、リフレクションじゃないから属性とか属性パラメータの取り方がちょっと特殊。MSDN最高。基本すべてソースコードを解析した結果構築されるオブジェクト達だから中身は単なる文字列。arg.Valueで取り出したActionNameに指定してるName値がソース上で定義されてるのと同じようにダブルクォーテーション付きになってるので、そこを削除。

最後にテンプレート部で処理してる部分を書き換え。

public static class MVC {
<#  foreach (var controller in Controllers) { #>
    public static <#= controller.DerivedClassName #> <#= controller.Name #> = new <#= controller.DerivedClassName #>();
<#  } #>
}

まずはMVCクラスの部分でオリジナルControllerクラスを入れ物にしてたから、テンプレートで生成した派生クラスになるように変更。こうしないとActionName名のアクション関数が無いから困るんです。

namespace <#= T4MVCNamespace #> {
<#  foreach (var controller in Controllers.Where(c => !c.SharedViewFolder)) { #>
    [CompilerGenerated]
    public class <#= controller.DerivedClassName #>: <#= controller.FullClassName #> {
        public <#= controller.DerivedClassName #>() : base(_Dummy.Instance) { }

<#      foreach (var method in controller.ActionMethods) { 
        var overrideKeyword = method.IsOverride ? "override " : "";
#>
        public <#= overrideKeyword #><#= method.ReturnType #> <#= method.Name #>(<# method.WriteFormalParameters(true); #>) {
            var callInfo = new T4MVC_<#= method.ReturnType #>("<#= controller.Name #>", "<#= method.Name #>");
<#          if (method.Parameters.Count > 0) { #>
<#              foreach (var p in method.Parameters) { #>
            callInfo.RouteValues.Add("<#= p.Name #>", <#= p.Name #>);
<#              } #>
<#          }#>
            return callInfo;
        }

<#      } #>
    }
<#  } #>

    [CompilerGenerated]
    public class _Dummy {
        private _Dummy() { }
        public static _Dummy Instance = new _Dummy();
    }
}

上記太字の部分で最後です。無駄にソースを引用してるんで、長いですけど、実質10行ほどじゃないっすかね。思ったより、変更箇所も少なくて助かりました。Visual Studioオートメーション&T4の組み合わせ恐るべし。

そうすると、前回の投稿ではIntelliSenceに出てこなかったActionName指定の部分も出てくるようになりました。

t4mvc4

やったね!

これまた興味ある方はダウンロードどうぞ(T4MVC-T.ttに名前変えてます)。

T4MVC

べーさんも気になってるように、ASP.NET MVCでは文字列(マジックストリング)を指定して、リンクやURLを生成するのが普通ですね。

    <% using(Html.BeginForm("Index","Home")) { %>
      <% = Html.TextBox("Name") %>
      <input type="submit" value="ポスト" />
    <% } %>

例えば、↑こんな感じで書くと↓こんな感じの出力に。

    <form action="/" method="post">
<input id="Name" name="Name" type="text" value="" /> <input type="submit" value="ポスト" /> </form>

リンクの場合もそう。

    <% = Html.ActionLink("ホーム", "Index") %>

↑こんな感じでしょう。URL生成はコントローラとアクションを指定したり、ルーティング名を指定したりするのが、今までのオーソドックスな書き方。

そんな状況は誰も嬉しくないよ!だってアクション名変えたら、指定してる箇所全部検索して変更しなきゃ行けないし、1文字でも間違ってたらちゃんと出力してくれない。あぁ、誰か助けて。

そもそもの始まりは↓ここからでした。

Angle Bracket Percent : A BuildProvider to simplify your ASP.NET MVC Action Links

BuildProviderを使ってASP.NET実行時に、CodeDom使ったコンパイラを走らせてがんばる方法(自アセンブリをリフレクションで探索)。なるほど~、と。ただ、やっぱり応用しにくいっていうか、コードが書きにくい感じで、その時はそれほど便利でもないかな~、なんて油断してました。それでも、この時点でHtmlHelperを拡張して、文字列指定じゃなくて関数指定でリンク生成出来てました。この辺でPhilさんもエントリ上げてて、ActionNameで別名使ったときにこれだと対応出来ないから、その辺上手いこと処理出来るのを次のバージョンに向けて考えてます的なことを言ってた気がする。

その後、いろいろ試行錯誤があって、出てきたのが↓これですよ。

Angle Bracket Percent : A new and improved ASP.NET MVC T4 template

CodeDomじゃなくてT4でいいんじゃね?と気がついたんでしょうか。コード生成するならこういうテンプレートエンジン使った方が断然生産性が高いしね。このときはまだMvc-CodeGenっていう名前だったんですが、これを更にブラッシュアップして出てきたのが↓。

Angle Bracket Percent : T4MVC 2.2 update: Routing, Forms, DI container, fixes

ちょっとバージョンアップしたんだけど、T4MVCに名前変わってからはMVCのソースが公開されてるCodePlexに組み込まれました(アドインだからこういう言い方はおかしいかも?)。

ASP.NET - Release: ASP.NET MVC v1.0 Source

ドキュメントなんてかけらもないので、どういう物かはソースを見て判断しましょう。まぁ、TTファイルの最初に書かれてる内容がそのままなんですけどね。

とにかくまず、自分のMVCプロジェクトのルートにT4MVC.ttをコピー。準備はこれだけ。後はT4なんで勝手にコード生成してコンパイルしてくれるので、すぐに使い始められます(最初にApp_Codeに放り込んでみたら全然動かなくてビックリした)。

t4mvc1

大枠でMVCという静的クラスが生成されて、そこからたどっていく感じになります。ASP.NETでも自動生成されるグローバルクラスにASPっていうのがあるけどそれと同じような感覚ですね。とりあえず、最初に書いたサンプルをT4MVCで書くとどうなるか、ですが、↓こうです。

    <% using(Html.BeginForm(MVC.Home.Actions.Index, MVC.Home.Name)) { %>
      <% = Html.TextBox("Name") %>
      <input type="submit" value="ポスト" />
    <% } %>

    <% = Html.ActionLink("ホーム", MVC.Home.Index()) %>

リンクに表示する部分以外のマジックストリングが無くなりました。しかもこのMVCクラスは動的なので、アクションやコントローラの名前を変更したら、コンパイルエラーが起きるので、変更し忘れともおさらばですよ!素敵です。

これだけじゃなくてデスね、Linksというクラスも同時に生成されるんですが、そこにはContentフォルダとScriptsフォルダに含まれてるファイル達のリンクが生成されます。

    <% = Links.Content.Site_css %>
    <% = Links.Scripts.jquery_1_3_2_js %>

↑こんな感じで。

さて、ここでActionNameAttributeをつけたアクションはちゃんと指定出来るのか気になるところなので、簡単に実験してみましょう。

    [ActionName("Index2")]
    public ActionResult KoukaiShitakunaiNamaeNoAction()
    {
      return View("Index");
    }

こんなのを作成してみる。保存したりすると、勝手にT4MVCが動く。で、ViewでIntelliSenceをきかせてみると~?

t4mvc2

残念!ActionNameまでは見てくれませんでした。Index2が出てくるのを期待したんだけど。実行結果も残念ながら。元の名前のままでした。がんばって自分でtt書き換えてActionName属性を見るようにするか、おとなしく新しいバージョンを待つか。どっちが男らしい?

ところで、このT4MVCを実行するとすべてのコントローラはpartialクラスになって、すべてのアクションはvirtualが自動でくっつきます。どうしてかというと、ActionResultを引数に受け取るHtmlHelper拡張に渡して、URLを生成しやすくするためですよね。内部で独自クラスに派生させたコントローラを生成し、アクションをオーバーライドしてるんですね。なんとも強引な方法。コントローラ書き換えられるのが気持ち悪い!って人にはお勧めしないですけど...。

お試しあれ!

dotnetConf2015 Japan

https://github.com/takepara/MvcVpl ↑こちらにいろいろ置いときました。 参加してくださった方々の温かい対応に感謝感謝です。