The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

寫 ASP.NET 可利用 <asp:PlaceHolder> 降低 ViewState 大小

前幾天在調整一個網站的執行效能時,發現有幾頁的 ViewState 特別大,但是內容卻蠻簡單的,最主要就是一個 Repeater 控制項,內容不多,但 ItemTemplate 中只有用到一個 LinkButton 控制項,其他都是一般的 HTML 標籤加上 DataBound 語法 ( <%# Eval("XXX", "") %> ),由於我有用到 UpdatePanel 包住這個 Repeater 控制項,所以我 ViewState 不能關閉,關閉就會導致錯誤發生,所以我只能在 ItemTemplate 盡可能降低 ViewState 的使用,不過就因為除了 LinkButton 控制項之外的地方我都沒有可以調整的地方,才讓我想到還有個 PlaceHolder 控制項可用。

我簡單做了個範例說明這��件事,但我把 LinkButton 移除了,單純介紹在 Repeater 的 ItemTemplate 中的語法如何會佔用 ViewState 空間:

Default.aspx

<%@ Page Trace="true" Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<html><body><form id="form1" runat="server">
    <asp:Repeater ID="Repeater1" runat="server"> <HeaderTemplate> <ol> </HeaderTemplate>
    <ItemTemplate>
        <li><a href="<%# Eval("URL", "") %>"><%Eval("TITLE", "")%></a></li>
    </ItemTemplate>
    <FooterTemplate> </ol> </FooterTemplate> </asp:Repeater>
</form></body></html>

Default.aspx.cs

using System;
using System.Collections.Generic;

public partial class _Default : System.Web.UI.Page
{
    class DataItem
    {
        public string URL { get; set; }
        public string TITLE { get; set; }

        public DataItem(string _url, string _title)
        {
            this.URL = _url;
            this.TITLE = _title;
        }
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        List<DataItem> data = new List<DataItem>();

        data.Add(new DataItem("http://www.miniasp.com/", "多奇數位"));
        data.Add(new DataItem("http://blog.miniasp.com/", "The Will Will Web"));
        data.Add(new DataItem("http://msg.nat.gov.tw/", "我的貼身e管家"));

        Repeater1.DataSource = data;
        Repeater1.DataBind();
    }
}

在以上範例中,你會看到在 ItemTemplate 中有出現一段

<li><a href="<%# Eval("URL", "") %>"><%Eval("TITLE", "")%></a></li>

但是我開啟 Page Trace 之後,卻發現這一段是會佔用不少 ViewState 的,而且會將原本應該產生 LiteralControl 的,因為使用了 DataBound 的語法而被轉成 DataBoundLiteralControl 控制項,而這個控制項是會保留 ViewState 的,但我們在 *.aspx 頁面中卻無法關閉:

控制項樹狀結構

所以我在這些 HTML 資料的前後加上一個 PlaceHolder 控制項,並設定 EnableViewState 為 false 就可以把 ViewState 全部關掉了,若你 ItemTemplate 中的資料量很大的話,可省下的空間不可小覷。

更新過的 Default.aspx 如下:

<%@ Page Trace="true" Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<html><body><form id="form1" runat="server">
    <asp:Repeater ID="Repeater1" runat="server"> <HeaderTemplate> <ol> </HeaderTemplate>
    <ItemTemplate>
    <asp:PlaceHolder runat="server" ID="PlaceHolder1" EnableViewState="false">
        <li><a href="<%# Eval("URL", "") %>"><%Eval("TITLE", "")%></a></li>
    </asp:PlaceHolder>
    </ItemTemplate>
    <FooterTemplate> </ol> </FooterTemplate> </asp:Repeater>
</form></body></html>

若想看由 ASP.NET 自動產生的 *.cs 程式原始碼的話,可以修改 web.config 中在 <system.web> 底下的 <compilation debug="false"> 改成 <compilation debug="true"> 後,重新執行一遍這一頁,再到 Temporary ASP.NET Files 目錄下查看產生過的原始碼即可,通常這個目錄預設會放在以下路徑:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files

相關連結