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を生成しやすくするためですよね。内部で独自クラスに派生させたコントローラを生成し、アクションをオーバーライドしてるんですね。なんとも強引な方法。コントローラ書き換えられるのが気持ち悪い!って人にはお勧めしないですけど...。

お試しあれ!

わんまるとキャプテンわん

横浜開港150周年記念キャラクターのたねまる。最近まで知らなかったけどこんなのいたのか。電車の車体に貼られてるのを見て知った。

たねまるドットコム|横浜開港150周年マスターライセンシーオフィス公式サイト

tanemaru

そして、どうやら彼女がいるらしい...。

で、キャプテンわん。わんまるとか適当な名前で教えられたけど、これも横浜がらみ。ハマスポのキャラクターらしい。

wan

キャプテンわんコーナー

「落ち込んだら走れ!」って言われた。上のページでちょいちょいメッセージが切り替わって、熱血漢なところをアピール。さすがハマスポ。

写真

そして↑これがガッカリなキャプテンの写真(拡大してみるとガッカリ度さらにアップ)。あまりにもガッカリな状況だ...。こんな写真をアップしてたら訴えられるんじゃないかとヒヤヒヤする。前にも書いたかな~、この横浜市の体育協会の広報資料になぜかたけはらさんの写真が載ってるよ!ファンはゲットしときましょう。

そんな話はいいとして、今日は負けられないレギュラーシーズン最終戦。負けてもギリギリプレーオフには行けるらしいけど、あまりにもギリギリだと初戦から強豪と対決になって気が滅入るので、今日の試合は何が何でも勝っておきたいところ。とは言いつつも、最終戦の相手が一番の強豪だったりしないですかね。ファルコンズって...。ワカバヤシ兄弟で出るって空気読めてないゴールド戦士には出場をご遠慮願いたい。朝一8時30分開始の試合だからあわよくば来てくれるなと思ってたけど、ちゃんといた。「S40と木場マーボーズの試合だけは絶対出る」と本人談。君たちはアレだろ、消化試合というか、調整試合だろ。こっちはプレーオフかかってんだ。もうちょっと空気読んでくれよ。とりあえずケースケは来て無くていなくてホッとした。

ところで、前回の試合の感想を宿題にしといたんだけど、その提出がなかなか無くてさ。ミサキ姫に問い詰めたら、今回の試合と合わせて2試合分をまとめて提出すると、自分でハードル上げてきた。若さって怖い。平成生まれって強い。

試合内容はね~、あれっすよ、大接戦っすよ。試合開始早々相手のペナルティー(やられた身としてはそうでもなかったけど、ここはありがたくチャンスを頂戴しとく)で、パワープレー。シンゴ→タケ→オグでバシッと決めて、さい先のいい試合展開。聞いた話によると、相手ゴーリーはウォールがかかってるらしい。今日の試合次第でベストゴーリーになるほどの鉄壁君だって。それが、序盤そうそうに失点しちゃったもんだから、気持ちも折れるってもんですよ。やったね。そっから、取りつ取られつの試合展開で、あ!っという間に3分(早っ)。まだ同点だったけど、ここで点を取れればというところで、セト君が決めてくれて1点リードで逃げ切り体制。に、持って行きたかったけど、直後のフェイスオフでツトム君に真ん中から突破されてわずか8秒で再度同点。なんじゃそれ!でも、最後はオグさんがバシッと決めて見事な勝利。もう満足。ぶっちゃけプレーオフもういいじゃん、ってくらい出し切った。他の試合結果次第だけど、カネコさんがウォールになりそうなのもちょっと楽しみ。

そもそも、今日もうちはゴーリーがいないはずで、順番で自分がやるはずだったんだけど、どうしてもやりたくなくてタクちゃんに無理を言ってお願いしてきてもらったんだよね。しかも2週間前から連絡を取って、なんとか都合をつけてもらうという周到ぶり。おかげで勝てたよ!タクちゃんのグレートセーブで何度も助けられたし、シンゴの必死の守りで後半2失点で抑えられたのがよかった。と、言うことは前半の自殺点2点が無ければもっと楽に勝てたってこと?誰だ自分たちのゴールに蹴り込んだの!

...すいません。シンタロも一緒に謝っとけ。

久しぶりに7得点で7ポイントの大活躍な自分に拍手。