Web最適化シリーズ3:圧縮後viewstateの使用

15025 ワード

Asp.Netのサーバコントロールはviewstateを有効にしており、開発者を便利にしていますが、ページのサイズや性能には確かに影響があります.viewstateを必要としないコントロールやページについては、コントロールやページのviewstateを直接無効にすることができますが、必要なviewstateについては、別の方法で処理することができます.圧縮.viewstate圧縮が必要かどうかを判断するガイドラインは、イントラネットシステムが圧縮を考慮する必要はありません(ネットワーク速度が速くて暇なのにサーバCPUリソースを消費して何をしているのか...).対外システムはviewstate長に基づいて選択的に圧縮する(viewstate長がある値より大きい場合に圧縮するが、短すぎると圧縮が損なわれないよ...)
さあ、次は具体的に展開しましょう.
一、viewstate圧縮:
ページのライフサイクルにviewstateを保存する方法はSavePageStateToPersistenceMediumメソッドなので、このメソッドを書き換えるとOKです.
 1  protected override void SavePageStateToPersistenceMedium(object state)
2 {
3 StringBuilder sb = new StringBuilder();
4 TextWriter tw = new StringWriter(sb);
5 LosFormatter lf = new LosFormatter();
6 lf.Serialize(tw, state);
7 tw.Flush();
8 tw.Close();
9 tw.Dispose();
10 bool useZip = false;
11 string finalStr = sb.ToString();
12 if (sb.Length >= 1096)
13 {
14 useZip = true;
15 byte[] bytes = Compress(Convert.FromBase64String(finalStr));
16 finalStr = Convert.ToBase64String(bytes);
17 }
18
19 ClientScript.RegisterHiddenField("_MyViewState", finalStr);
20 ClientScript.RegisterHiddenField("_UseZip", (useZip?"T":"F"));
21 }
22
23 private byte[] Compress(byte[] data)
24 {
25 MemoryStream ms = new MemoryStream();
26 GZipStream gzip = new GZipStream(ms, CompressionMode.Compress);
27 gzip.Write(data, 0, data.Length);
28 gzip.Flush();
29 gzip.Close();
30 gzip.Dispose();
31
32 byte[] bytes = ms.ToArray();
33 ms.Close();
34 ms.Dispose();
35
36 return bytes;
37 }

1.入力されたパラメータstateは、ページのすべてのviewstateコレクションオブジェクトであり、デフォルトではシーケンス化されて__に保存されます.ViewStateの非表示コントロールにあります.したがって、LosFormatterオブジェクトを用いてstateオブジェクトをシーケンス化する場合、得られるシーケンス化文字列は68ビットの数に基づいて符号化される.
2.1096はviewstate長が1096より大きい場合に圧縮され、そうでない場合はそのままであることを示す.
3..NetにあるシステムIO.Compressionには2つの圧縮方式がありますが、ここではGZipを選択し、他のより良い圧縮アルゴリズムの方法でも、圧縮効果が良い^^!
4.圧縮が完了すると68ビットの数をベースとした符号化文字列が__に保存されるMyView Stateの非表示コントロールでは、デフォルトの__を使用できないことに注意してください.ViewStateは保存されます.そうしないとエラーが発生します.
 
圧縮された部分は、もちろん解凍されていますが、返信時にLoadPageStateFromPersistenceMediumメソッドでviewstateを取得するので、書き直しましょう
 1   protected override object LoadPageStateFromPersistenceMedium()
2 {
3 string myViewState = Request.Form["_MyViewState"];
4 bool useZip = (Request.Form["_UseZip"].Equals("T")?true:false);
5 LosFormatter lf = new LosFormatter();
6 if (useZip)
7 {
8 byte[] bytes = Convert.FromBase64String(myViewState);
9 bytes = Decompress(bytes);
10
11 return lf.Deserialize(Convert.ToBase64String(bytes));
12 }
13 else
14 {
15 return lf.Deserialize(myViewState);
16 }
17 }
18 private byte[] Decompress(byte[] data)
19 {
20 MemoryStream ms = new MemoryStream(data);
21 GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress);
22 byte[] resultByte = null;
23 int count = 1;
24 MemoryStream resultMs = new MemoryStream();
25 while (count >= 1)
26 {
27 resultByte = new byte[1024];
28 count = gzip.Read(resultByte, 0, 1024);
29 resultMs.Write(resultByte, 0, count);
30 }
31 resultByte = resultMs.ToArray();
32 resultMs.Close();
33 resultMs.Dispose();
34 gzip.Close();
35 gzip.Dispose();
36 ms.Close();
37 ms.Dispose();
38
39 return resultByte;
40 }

1.から_MyView Stateでviewstate文字列を取得し、次に解凍、逆シーケンスを取得し、以前に保存したView Stateオブジェクトを取得します.
 
これでViewStateの圧縮はKOになります.もちろんNetはViewStateをSessionに保存することもでき、設定すれば良いので、非常に便利で、自分で複数ページに現れるViewStateオーバーライドの問題を処理しないようにします.
 
二、後置ViewState(2011.12.12補正)
viewstateはデフォルトでページの先頭に保存されていますが、長すぎると検索エンジンがこのサイトに登るのに一定の影響がある場合は、ViewStateをページの最後に置くことで最適化できます.後にviewstateを置くメリットは、ページが早く出ることですよ.
 1  protected override void Render(HtmlTextWriter writer)
2 {
3 StringWriter sw = new StringWriter();
4 HtmlTextWriter htw = new HtmlTextWriter(sw);
5 base.Render(htw);
6 htw.Flush();
7 htw.Close();
8 htw.Dispose();
9 StringBuilder resulteHtml = new StringBuilder(sw.ToString());
10 sw.Close();
11 sw.Dispose();
12
13 Regex reg = new Regex("<input type=\"hidden\" name=\"_MyViewState\" id=\"_MyViewState\" .* />");
14 string myViewState = reg.Match(resulteHtml.ToString()).Value;
       if(!string.IsNullOrEmpty(myViewState))
      {
15   resulteHtml.Replace(myViewState, string.Empty);
16 resulteHtml.Append(myViewState);//
         int formEndTag_index=resulteHtml.ToString().IndexOf("</form>");
             resulteHtml.Insert(forEndTag_index,myViewState);
17           reg = new Regex("<input type=\"hidden\" name=\"_UseZip\" id=\"_UseZip\" .* />");
18   myViewState = reg.Match(resulteHtml.ToString()).Value;
19   resulteHtml.Replace(myViewState, string.Empty);
20 resulteHtml.Append(myViewState);//
 
 
         formEndTag_index=resulteHtml.ToString().IndexOf("</form>");
 
 
             resulteHtml.Insert(forEndTag_index,myViewState);
       }

21 Response.Write(resulteHtml.ToString());
22 }
Render                     (     HttpModule ),base.Render()          html     HtmlTextWriter
   ,             html   ,           viewstate  ,    html     ,           ,     
     ,         。
2011.12.12    :
   1.              html       :....</form><input type="hidden" id="_MyViewState" name="_MyViewState"... ,
 postback  LoadPageStateFromPersistenceMedium       form  ,     form["   "]   。             </form
>    。

   2.myViewStateが空の文字列であるか否かを判断する目的はajaxを用いる.Net時にrenderが得るコンテンツには、以前にカスタマイズした非表示コントロールが含まれておらず、stringを防止する.replaceでoldvalueが空の場合に異常を放出します.
  3.ページがajaxを使用する場合.Netでこのベースクラスを使ってviewstateを処理すると、UpdatePanelコントロール内の更新、削除操作が無効になります.原因はしばらく分かりませんが、皆さんは良い方法がありますか?教えてください!
上一篇:ウェブページの最適化シリーズ4:Asp.Netの5種類のキャッシュ方式