2008年4月25日金曜日

ViewUserControlが恋しい

ASP.NET MVCと相変わらず格闘中。 で、Ajax的な機能を組み込んでるところで、とうとうViewUserControlのみのレンダリングが必要になってきました。ハァ~。先延ばしにしてもどこかに答えが出てくるわけじゃないんだな~。人気なさそうだしな~。

次のバージョンでどのくらい実装に変化が出るのかドキドキしつつ、とりあえずはPreview 2のソースを追っかけてどうやろうか思案。ViewEngineを実装したところで、ViewUserControlのレンダリング結果が欲しいだけなんだから、あんまり意味ない(よね?)。

とうとう、あれか、ComponentControllerの出番か。とか思ってサンプル作ってみたけど、全然関係なさげ。 ComponentController and ActionResult - ASP.NET Forums こんなの見ると萎える...。

ViewUserControlとComponentControllerはコンテキストが違うっつーだけなんすかね。 コントロールは同一コンテキスト(パイプライン)の中で、同じViewEngineに対してレンダリングするけど、コンポーネントは別のViewEngineへの出力を取得して、それを現在のコンテキストにマージ。そんな感じ? まぁ、いいや。 で、どうすっかな~とMVCのソースを眺めてたんだけども、UserControlExtentionsのコードをオマージュすればいいってところにたどり着きました。 最低限以下のコードをコントローラに書けばOKっす!

      ViewContext vc = new ViewContext(ControllerContext, "dummy", "", null,null);
      var page = new ViewPage();
      page.Html = new HtmlHelper(vc);

      string partial_html = page.Html.RenderUserControl("仮想パス/コントローラ.ascx");
      Response.Write(partial_html);

Pageの実体を参照しないViewContextを作って、空のViewPageにHtmlHelperと一緒に割り当て。 コントロールの中でUrlHelper使うなら、それもセットしておきましょう。

      page.Url = new UrlHelper(vc); 

もちろん、RenderUserControlだから独自ViewDataも渡せるし、そこは普通に。 無駄にPageインスタンス作るのが納得いかないけど、オリジナルもその手法だからこれでよかろうさ。 これで、HTMLの部分更新もコントロールをそのまま使って実装できるから簡単になるよね!