Asp.Netエンタープライズソリューションパターン その2 ページコントローラ

前から十日あいてるじゃん。Lispの方が面白くてさ・・・。

勉強するにあたって、自分がやってるあいだ自分が何考えてるのか詳細に記録したくなった。
なんか異様に時間かかるから。

作業のログをとりながらやってみた結果がこれ。
脇道にそれて調べるてて時間がかかってるっぽい。
まぁそれはしょうがないか。


ページコントローラ
MVCのコントロラ部の実装指針の一つ。別解がフロントコントローラ。
ASP.NETはページコントロラ指向。Winformぽく開発させたかったらそうなるよな。

本ではヘッダ部分をインクルードファイルにしているが、これをマスターページに変更したい

マスターページ(Header.Master)、ページ(Page1.aspx)を作成して、Page1.aspxのMasuterPageFileにHeader.Masterを設定したが、
「コンテンツ コントロールは、コンテンツ ページまたはマスタ ページを参照する入れ子にされたマスタ ページでトップ レベルのコントロールでなければなりません。」
とエラー。
こういう使い方ではないらしい。

11:54
http://www.microsoft.com/japan/msdn/thisweek/300x10/Phase3/masterpage/cs.aspx
を見る。

マスターページ
ContentPlaceHolderタグを書く。
これがコンテンツを置く場所になる。ContentPlaceHolderは複数配置可能。
はなく、マスターページのものが使われるらしい。
(これってどうなんだろ??htmlのタイトルはマスターページじゃなくてコンテンツになるページで定義したくないか??
Loadで書き直せばいいにせよ・・・)

コンテンツページ
ページディレクティブでマスターぺージを指定
<%@Page MasterPageFile="~/xxx.master" .... %>

Contentコントロールに各ページのコンテンツを書く。
ContentPlaceHolderIDにマスタぺージのContentPlaceHolderのidを指定して配置場所を指定。

ふむ。関連付けの方法はわかった。
しかしこれでは、マスターページを使用する場合としない場合でaspxファイルの内容がまったく変わるじゃん。
コンテンツになるページはコンテンツページとかいう名前にして、拡張子もわけちゃった方が良かったのではないか?
と疑問がわく。

12:05
やり方はわかったから実装。
新規aspxを作るときにマスターぺージを指定するチェックをつけると、マスタページを使用する内容でデフォルトのaspxファイルを作ってくれるけど、天の邪鬼なので手でやることにする。

12:08
あー、そういうことか。
マスターページのヘッダ部分にもContentPlaceHolderタグがある。
タイトルとか、各ページに持たせたい部分はこの中にかけってことか。
納得。

12:13
HTMLコントロールにSapnがないのはなんでだろう??

12:19
スタイルシートの指定はxxx:値の形式で;区切りであることを忘れていた。記憶力が落ちてないか

12:22
マスタページを作り中・・・。
aspxコントロールでデザインをスタイルシートで指定したいときにはどうしたらいんだ??
VS上での設定がどうhtmlに展開されるのかわからない。
動かすしかないか。
ForeColorはStyleでの指定になってた。
外部スタイルシートを使いたいときにはどうすんだろ?
おお、CssClassというのがあった。
あとSkinIDも怪しい。

12:32
マスタページできた。時間かかりすぎ・・・。
いや、マシンが非力だし、あちこちいじりながらだし、このテキストも書いてるし・・・。

ページを作る。

12:34
デフォでマスタページにFormがあるのはどうなんだ??
コンテンツに持たせるケースのが多くないのか?
いや、まてよ。どうせポストバックして自分にポストするのがAsp.Netだからマスタページにあっていのか。

12:40
ページできた。
ノートPC遅え。
ちょっと休憩

12:44
復帰。ロジック書くか。
Loadが呼ばれる順番ってどうなんだろ。
マスタページ→コンテンツだよね。
確かめる。
IEの起動遅い。
コンテンツ→マスタ
だった。えぇえぇ。逆じゃないの??

調べる。
http://msdn2.microsoft.com/ja-jp/library/dct97kc3.aspx
Initはマスタページが先なのか。
うーん。きっとコンテンツの方が先に走った方がいいからこうなってるんだよね?
Initっていつ呼ばれるんだ??
http://msdn2.microsoft.com/ja-jp/library/ms178472(VS.80).aspx
ここに説明があった。
が、InitとLoadの差がわかんない。調べる。

Initはボトムアップ(子コントロールから)
Loadはトップダウン(親コントロールから)
の順でイベントが起きるらしい。

http://blogs.wankuma.com/jitta/archive/2005/11/24/19572.aspx

Init→ViewState復元→ポストバックデータ処理→Loadとなるのか。
ふむ。
なら、Initではテキストボックスの値とかまだ取れないのかな?
やってみる。

つか、Page_LoadとかPage_Initとイベントの関連付けってどうやってるんだろ。
そっちさきに調べる。

http://msdn2.microsoft.com/ja-jp/library/ms227455.aspx
PageディレクティブのAutoEventWireupがTrueだと、勝手にイベントとの関連付けをするらしい。
シグニチャだけで関連付けるから、タイプミスには注意。
この辺のオートマ具合がMSだなぁ。個人的には気持ち悪い。

勝手に関連づけられるのは

</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_Init</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_DataBind</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_PreRender</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_Unload</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_Error</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">マニュアルには書いてない(らしい)けど以下も
</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_AbortTransaction</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">OnTransactionAbort</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">Page_CommitTransaction</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">OnTransactionCommit</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">で、Init。</asp:contentplaceholder>
<asp:contentplaceholder id="xxx">試してみたら確かにポストバックされたデータはまだ復元されてない。

よしよし。

13:31
調べてただけでこんな時間に。
またロジック書いてないじゃん。つか、その前にDBつくらな。
今回もDLINQで行くつもり。

14:17
エアコン工事が来てたので中断しつつも完成。


まとめ
MVCと特に変わりはなくて、この章で追加されたことは各ページの共通処理を抽象クラスにまとめようね、ということだけ。
ただ、マスタページを使えば大抵は事足りる、のかもしれない。
PageのLoad前後に共通処理がある場合なんかはやっぱりBasePageとなる抽象クラスを作った方がいいのかも。

ソース
PageBase.master

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="PageBase.master.cs" Inherits="Header" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="headerForm" runat="server">
    <div style="background-color: #9c0001">
        <span style="font-size: small; color:#ffffff">ようこそ</span>
        <asp:Label ID="eMail" runat="server" Font-Size="Small" ForeColor="White" Text="xxx"></asp:Label>
    </div>
    <div style="font-size: x-large; color: #ffffff; background-color: #d3c9c7;">
        <asp:Label ID="siteName" runat="server" Text="xxx"></asp:Label>
    </div>
    <div>
        <asp:ContentPlaceHolder id="body" runat="server">
        </asp:ContentPlaceHolder>
    </div>
</form>
</body>
</html>

PageBase.master.cs

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;

public partial class Header : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (this.IsPostBack)
        {
            return;
        }

        this.eMail.Text = AspnetStudyGateway.GetAddress(
            this.Context.User.Identity.Name);
        this.siteName.Text = "MacroSite";
    }
}

Page1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Page1.aspx.cs" Inherits="Page1" MasterPageFile="~/PageBase.master" %>
<asp:Content ID="hederContent" ContentPlaceHolderID="head" runat="server">
    <title>ページ1</title>
</asp:Content>
<asp:Content ID="bodyContent" ContentPlaceHolderID="body" runat="server">
    <div style="font-size: xx-large">
    ページ<asp:Label ID="pageNumber" runat="server" Text="xxx"></asp:Label>
    </div>
</asp:Content>

Page1.aspx.cs

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

public partial class Page1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.pageNumber.Text = "1";
    }
}

AspnetStudyGateway.cs

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;


public class AspnetStudyGateway
{
    public AspnetStudyGateway()
    {
    }

    public static string GetAddress(string id)
    {
        var u = from user in Context.webusers
                where user.id == id
                select user;

        return u.First().address;
    }

    private static Aspnet_studyDataContext Context
    {
        get
        {
            var con = new Aspnet_studyDataContext(
                "Data Source=Gerbera;Initial Catalog=aspnet_study;User ID=sa;Password=p");
            return con;
        }
    }
}