2011年8月14日日曜日

Controllerを名前から生成するしHTMLを書き換えたりもしてみる

Developer @ ADJUST : ASP.NET MVC のコントローラクラスを、コントローラ名から取得したいのだけれど...結局、ぜんぶ列挙!?

前回のエントリーからはや1ヶ月以上経過したこのブログ。エアコンが壊れてて、バリバリ節電に貢献できてる気はするけど、辛い毎日でブログどころではないですよ!

で、坂本さん、上記の件ですが以下のような方法はいかがでしょうか。単純に型が欲しいだけならインスタンスは不要なので無駄な感じはしなくもないですが。必要なのがインスタンスであれば一番いい方法だと思います。

var factory = ControllerBuilder.Current.GetControllerFactory();
var controller = factory.CreateController(Request.RequestContext, "Home");
var type = controller.GetType();
factory.ReleaseController(controller);

コレと言って、自信で発明したものはなく、やってることはMvcHandlerでやってることと同じです。MvcHandlerってあれです、MvcRouteHandlerが返してくるIHttpHandlerのことです。

内部でタイプキャッシュとかしてくれてるので、パフォーマンスには自信があります!あると思います!

ここから別件。

もう暑さで脳みそが働かない...。けど、これだけじゃ坂本さんも納得しないと思うので、全然関係ない面白い機能紹介。といっても、URLRewrite 2.0の機能です。ハイパフォーマンスWebサイトの構築には必須のOutputCacheなんですが、クローラーなんかはUser AgentがCookieに対応してないと言ってくるじゃないですか。browserファイルで対応するのが王道ですが、それだと追従していくのが大変面倒くさい。

Creating Outbound Rules for URL Rewrite Module : URL Rewrite Module 2 : URL Rewrite Module : The Official Microsoft IIS Site

想定している状況を簡単にいうと、SessionのcookielessはuseDeviceProfile。PCサイトとケータイサイトを同一アプリケーションで実行。PCサイトは積極的にOutputCacheを利用し、ケータイサイトでは消極的(Viewでは使わない)に利用。この場合、PCサイトにクローラが来るとそのままではCookielessとしてセッションが生成されるので、OutputCacheにSessionIDを保持したHTMLが出力されてしまって都合悪い!

ということなんですが、伝わるでしょうか...。

OutputCacheをVaryByUserAgentにするのも手ですね。いろいろ方法はあると思うんですけど、こないだ試したのがPCサイトの場合、出力されるHTMLにSession IDが含まれることが正常系ではありえないので、PCサイトの場合、Response.FilterでURLにSession IDが含まれてたら消してしまうという方法。Response.Filterでやるよりももっと簡単なのがURL Rewrite 2.0の出力書き換えを利用するっていう方法。どうですか、面白そうじゃないですか?

ちなみにOutbound Rule用に独自Provider書いたりもできるけど、そこまでやることはあんまりないかなー、と思いますがどうでしょう。

<rewrite>
  <outboundRules>
      <rule name="Sessionless" preCondition="html" enabled="true">
          <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script, CustomTags" customTags="All" pattern="(.*)/\(S\([0-9a-z]+\)\)(.*)" />
          <action type="Rewrite" value="{R:1}{R:2}" />
          <conditions>
              <add input="{REQUEST_URI}" matchType="Pattern" pattern="\)/mobile" ignoreCase="true" negate="true" />
          </conditions>
      </rule>
      <customTags>
          <tags name="All" />
      </customTags>
      <preConditions>
          <preCondition name="html">
              <add input="{RESPONSE_CONTENT_TYPE}" pattern="text/html" />
              <add input="{REQUEST_URI}" pattern="/mobile" negate="true" />
          </preCondition>
      </preConditions>
  </outboundRules>
</rewrite>
<urlCompression doDynamicCompression="false" />

だいたいこんな感じの設定です。これをWeb.configに書いておきましょう。system.webServer配下です。ケータイサイトが/mobile配下という前提です。

実験。MVCサイトをデフォルトのまま生成し、Web.configに上記設定を追加しないで動作を確認。

この状態で出力されるのは↓。

cookieless1

そりゃそうですね。中身は↓。

cookieless2

なんてことないですよね。

今度はsessionStateのcookielessをUseUriにしてみましょう。見た目は同じなのでソースだけ。

cookieless3

画像をクリックして大きくしてみるとわかりますが、Session IDを含んだURLですよね。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Home Page</title>
    <link href="/(S(f4grns0hiatkwquk55qulbmd))/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/(S(f4grns0hiatkwquk55qulbmd))/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="/(S(f4grns0hiatkwquk55qulbmd))/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>My MVC Application</h1>
            </div>
            <div id="logindisplay">
                    [ <a href="/(S(f4grns0hiatkwquk55qulbmd))/Account/LogOn">Log On</a> ]
            </div>
...以下省略

今度は先のURLRewrite設定をOnにした場合。

cookieless4

あら素敵。ウソじゃないよ!URLにはちゃんとSession ID入ってるでしょ?

これでクローラが来てもOutputCacheにへんてこなものが仕込まれることないですね!あと、動的圧縮をオフにしてるのは既知です。設定いいんですけど今回はこれで。

役に立つやら立たないやらな情報でした!

dotnetConf2015 Japan

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