我前天遇到一個 ASP.NET 開發的問題,我有一個網站,其中有些頁面套用了一層的 MasterPage、有些套用了兩層 MasterPage、有些套用了三層 MasterPage,這些套兩層以上 MasterPage 的 MasterPage 在第二層的地方都是套用第一層的 MasterPage,不過客戶突然說第一層的 MasterPage 必須要依據不同的網域名稱(Domain Name)而選用不同的 MasterPage,最後耗了我三個小時才解決這個問題。
MasterPage 的套用關係大致的示意如下:
MasterPageTop.master
-> MasterPageChannel1.master
-> MasterPageChannel1_1.master
-> ContentPage.aspx
而我的需求是要動態變更 MasterPageChannel1.master 裡的 MasterPageFile 屬性,讓 ContentPage.aspx 在顯示的時候將 MasterPageTop.master 改成 MasterPageTop2.master。
問題與難點描述
一般來說,若 ContentPage.aspx 只有套一層 MasterPage 的話,只要在該頁面的 Page_PreInit 事件中指定 this.MasterPageFile 屬性即可動態變更該頁的 MasterPage,如下範例:
protected void Page_PreInit(object sender, EventArgs e)
{
if (Request.Url.Host == "www.mydomain.com")
{
this.MasterPageFile = "~/MasterPageTop2.master";
}
}
因為我有些頁面的 MasterPage 是套多層的,所以我就嘗試在 MasterPageChannel1.master 去設定 Page_PreInit 事件設定相同的程式碼,不過好像沒效果,程式完全沒有執行,經查詢後才得知原來 MasterPage 裡面並無 Page_PreInit 事件可以設定,最早的事件就是 OnInit 事件而已,所以從 MasterPage 去設定 MasterPageFile 是不可行的。
當下已經晚上九點,又還沒吃飯,感覺又好像是個無解的難題,不過總覺得不甘心就這樣放棄回家,一直拼到快 11 點才讓我寫出完美的解決方法。
動態修改巢狀 MasterPage 的 MasterPageFile 屬性的解決方案
既然從 MasterPage 去設定 MasterPageFile 是不可行的,那麼唯一個可能性就只有從內容頁面(ContentPage.aspx)下手了,因為所有前台 aspx 網頁都需要做出判斷,所以我寫了一個 BasePage,並覆寫(override) OnPreInit 事件,去動態修改頁面與每一層 MasterPage 中的 MasterPageFile 屬性(最多三層),而我的第一版 BasePage 寫成這樣:
/// <summary>
/// 讓所有前端的頁面繼承的共用 Page 類別
/// </summary>
public class FrontBasePage : Page
{
protected override void OnPreInit(EventArgs e)
{
if (Request.Url.Host == "www.mydomain.com")
{
if (this.MasterPageFile == "/MasterPageTop.master")
this.MasterPageFile = "~/MasterPageTop2.master";
if (Master != null)
{
if (Master.MasterPageFile == "/MasterPageTop.master")
Master.MasterPageFile = "~/MasterPageTop2.master";
if (Master.Master != null)
{
if (Master.Master.MasterPageFile == "/MasterPageTop.master")
Master.Master.MasterPageFile = "~/MasterPageTop2.master";
if (Master.Master.Master != null)
{
if (Master.Master.Master.MasterPageFile == "/MasterPageTop.master")
Master.Master.Master.MasterPageFile = "~/MasterPageTop2.master";
}
}
}
}
// 若有在內容頁面中有定義 Page_PreInit 事件的話會先在 base.OnPreInit(e) 執行!
base.OnPreInit(e);
}
}
其實這樣寫已經可以了,不過在我的頁面中卻無法正確的替換掉正確的 MasterPageTop2.master,原因就出在 base.OnPreInit(e); 這行。
若在內容頁面(Content Page)中有定義 Page_PreInit 事件的話會,真正呼叫這個事件執行的地方是在 base.OnPreInit(e) 內,而好巧不巧的我其中有一頁的 Page_PreInit 事件剛好也有寫到指定 MasterPageFile 屬性的程式,導致我在 FrontBasePage 所做出的設定到了 base.OnPreInit(e) 又被改回來了。
所以我最後我將 base.OnPreInit(e) 移到上面後,所有問題就都修復了!修改後的程式碼如下:
/// <summary>
/// 讓所有前端的頁面繼承的共用 Page 類別
/// </summary>
public class FrontBasePage : Page
{
protected override void OnPreInit(EventArgs e)
{
// 若有在內容頁面中有定義 Page_PreInit 事件的話會先在 base.OnPreInit(e) 執行!
base.OnPreInit(e);
if (Request.Url.Host == "www.mydomain.com")
{
if (this.MasterPageFile == "/MasterPageTop.master")
this.MasterPageFile = "~/MasterPageTop2.master";
if (Master != null)
{
if (Master.MasterPageFile == "/MasterPageTop.master")
Master.MasterPageFile = "~/MasterPageTop2.master";
if (Master.Master != null)
{
if (Master.Master.MasterPageFile == "/MasterPageTop.master")
Master.Master.MasterPageFile = "~/MasterPageTop2.master";
if (Master.Master.Master != null)
{
if (Master.Master.Master.MasterPageFile == "/MasterPageTop.master")
Master.Master.Master.MasterPageFile = "~/MasterPageTop2.master";
}
}
}
}
}
}
參考連結