คำนำ ตราบ
ใดที่คุณมีความเข้าใจเล็กน้อยเกี่ยวกับ ViewState คุณจะรู้ว่าโดยทั่วไปแล้ว ViewState ในหน้า Asp.net จะถูกจัดเก็บไว้ในฟิลด์ที่ซ่อนอยู่ของเพจ:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value=" Aพวงของยุ่งเรื่อง">
เมื่อเราเรียกดูไฟล์ต้นฉบับของหน้า เราจะเห็นสิ่งที่ยุ่งมากมาย (โดยเฉพาะเมื่อเพจมี DataGrid ที่มีข้อมูลจำนวนมาก หรือมี GridView ใน ASP.NET 2.0) เวลานั่นคือ ViewState
ความรู้พื้นฐาน
เนื่องจากมีการเปลี่ยนแปลงใหม่ในกลไกการคงอยู่ของ ViewState ใน ASP.NET 2.0 ฉันจะแนะนำสิ่งที่เกี่ยวข้องโดยย่อ
ใน ASP.NET 1.1 มีเพียงกลไกการคงอยู่ของโดเมนที่ซ่อนอยู่ของเพจเท่านั้น ดังนั้นในบางกรณี คุณต้องเลิกใช้ ViewState ลองนึกภาพดูว่ามีบันทึกนับหมื่นใน DataGrid ของคุณ (อย่าคิดอย่างนั้น) ซึ่งถือว่าผิดปกติ) ไม่จำเป็น (มีคนพบเห็น) หากเปิดใช้งาน ViewState คุณแน่ใจหรือไม่ว่าเซิร์ฟเวอร์ IIS ของคุณสามารถทนทานได้และเครือข่ายสามารถทนต่อได้หรือไม่ แน่นอน คุณสามารถเปลี่ยนกลไกการจัดเก็บข้อมูลของคุณได้โดยการแทนที่เมธอด Page.SavePageStateToPersistenceMedium() แต่อย่าลืมแทนที่ Page.LoadPageStateFromPersistenceMedium() ซึ่งเป็นคู่กัน
กลไกการคงอยู่ของสถานะมุมมองเริ่มต้นใน ASP.NET 2.0 ยังคงเก็บข้อมูลสถานะเป็นสตริงที่เข้ารหัส Base64 ในองค์ประกอบ HTML ที่ซ่อนอยู่บนเพจ (องค์ประกอบที่มีแอตทริบิวต์ประเภทที่ตั้งค่าเป็น "ซ่อน") เพจ ASP.NET ใช้วัตถุ HiddenFieldPageStatePersister เพื่อดำเนินการงานนี้และอินสแตนซ์ IStateFormatter เพื่อทำให้ข้อมูลสถานะของวัตถุเป็นอนุกรมและดีซีเรียลไลซ์ หรือสำหรับไคลเอนต์มือถือที่มีแบนด์วิธและทรัพยากรที่จำกัด คุณยังสามารถใช้คลาส SessionPageStatePersister เพื่อจัดเก็บสถานะมุมมองของเพจในอ็อบเจ็กต์เซสชันบนเซิร์ฟเวอร์ จริงๆ แล้ว มีกลไกการคงอยู่ของเซสชันเพียงหนึ่งเดียวเท่านั้น สถานะของเพจในเซสชันแทนที่จะเป็นในเพจซึ่งเป็นการประหยัดแบนด์วิธ
แต่ถ้าคุณต้องการทำความเข้าใจกลไกการคงอยู่ของ ViewState ให้ลึกซึ้งยิ่งขึ้น คุณควรรู้เกี่ยวกับคลาสนามธรรม PageStatePersister เพื่อรักษาสถานะการดูบนไคลเอนต์ที่ไม่สามารถรองรับกลไกการคงอยู่ของสถานะการดูที่มีอยู่ คุณสามารถขยายคลาส PageStatePersister และแนะนำ มุมมองของตัวเอง วิธีการคงอยู่ของรัฐและคุณสามารถใช้อะแดปเตอร์เพจเพื่อกำหนดค่าแอปพลิเคชัน ASP.NET เพื่อใช้กลไกการคงอยู่ของสถานะมุมมองที่แตกต่างกันตามประเภทของไคลเอนต์ที่ให้บริการเพจ คลาสที่ได้รับจากคลาส PageStatePersister จะต้องแทนที่เมธอด Save abstract เพื่อจัดเก็บสถานะมุมมองและสถานะการควบคุมในสื่อการคงอยู่ และแทนที่วิธี Load เพื่อแยกข้อมูลสถานะ หากคุณต้องการทำให้สถานะการดูเป็นอนุกรมและสถานะการควบคุมเป็นสตริง คุณสามารถใช้ออบเจ็กต์ IStateFormatter ที่เข้าถึงได้ผ่านคุณสมบัติ StateFormatter โดยจะอนุกรมและดีซีเรียลไลซ์ข้อมูลสถานะออบเจ็กต์ลงในสตริงที่เข้ารหัส Base64 ได้อย่างมีประสิทธิภาพ คุณยังสามารถแทนที่คุณสมบัติ StateFormatter เพื่อให้กลไกการทำให้เป็นอนุกรมของอ็อบเจ็กต์ของคุณเองได้ วิธีการทำเช่นนี้จะอธิบายไว้ในโค้ดของฉัน คุณจะเข้าใจได้ง่ายมาก
ฟิลด์
กลไกการคงอยู่ของ ViewState
จะไม่ถูกนำมาใช้ นี่คือฟิลด์เริ่มต้น ตามที่กล่าวไว้ในคำนำ
เซสชัน
จำเป็นต้องแทนที่คุณสมบัติ PageStatePersister ใน ASP.NET2.0 เท่านั้น
ป้องกันแทนที่ PageStatePersister PageStatePersister
-
รับ
-
กลับ SessionPageStatePersister ใหม่ (หน้า);
-
}
หากคุณต้องการแทนที่ LoadPageStateFromPersistenceMedium ทั้งสองวิธีนี้ใน ASP.NET1.1:
วัตถุแทนที่ที่มีการป้องกัน LoadPageStateFromPersistenceMedium()
-
กลับเซสชัน ["ViewState"];
}
การป้องกันแทนที่เป็นโมฆะ SavePageStateToPersistenceMedium (วัตถุ viewState)
-
เซสชั่น ["ViewState"] = viewState;
RegisterHiddenField("__VIEWSTATE", "");
}
ฐานข้อมูล (ตัวอย่างของฉันคือ SQL Server2000)
อยู่ใน ASP1.1 โปรดใส่ใจกับเส้นสีม่วงด้านล่าง ฉันไม่รู้ว่ามันใช้งานอะไร ทำให้ฉันรู้สึกหดหู่ใจไปหลายวัน . โค้ดต่อไปนี้ถูกคัดลอกมาจากซอร์สโค้ดของฉัน คุณไม่จำเป็นต้องเขียนแบบนี้เลย ยกเว้นโค้ดที่จำเป็น
การแทนที่การป้องกันถือเป็นโมฆะ SavePageStateToPersistenceMedium (สถานะของวัตถุ)
-
สตริง viewStateID = "VIEWSTATE#" + Session.SessionID.ToString() + "#" + DateTime.Now.Ticks.ToString();
ClientScript.RegisterHiddenField("__VIEWSTATE_KEY", viewStateID);
ClientScript.RegisterHiddenField("__VIEWSTATE","");//โปรดทราบว่า
ลอง
-
ถ้า (losFormatter == null)
-
losFormatter = ใหม่ LosFormatter();
-
StringWriter sw = StringWriter ใหม่ ();
losFormatter.Serialize (sw รัฐ);
Common.ViewStateData vsd = ViewStateData ใหม่ ();
vsd.ViewStateID = viewStateID;
vsd.ViewState = sw.ToString();
da = DataAccess ใหม่();
ข้อผิดพลาดสตริง = da.SaveViewState (vsd);
Response.Write (ข้อผิดพลาด);
-
catch (ข้อยกเว้น เช่น)
-
Response.Write (เช่น ข้อความ);
-
}
วัตถุแทนที่การป้องกัน LoadPageStateFromPersistenceMedium()
-
สตริง viewState = string.Empty;
พยายาม
-
ถ้า (losFormatter == null)
-
losFormatter = ใหม่ LosFormatter();
-
string stateID = Page.Request["__VIEWSTATE_KEY"].ToString();
da = DataAccess ใหม่();
viewState = da.LoadViewState (stateID);
-
จับ
{}
กลับ losFormatter.Deserialize (viewState);
}
ใด
จึงเป็นบรรทัดด้านบน ClientScript.RegisterHiddenField("__VIEWSTATE");
.net1.1 เป็นไปได้ ฉันยังอ้างถึงโค้ดของผู้อื่นและเพิ่มบรรทัดนี้ หลังจากเพิ่มบรรทัดนี้ มีเพียง <input type="hidden" name="__VIEWSTATE" value="" /> พิเศษบน
เพจ
มีสองสิ่ง
นี้ในไฟล์ต้นฉบับของเพจหลังจากรัน ลบบรรทัดนั้นก็ได้ครับ เลยไม่เข้าใจว่าใช้คำว่าอะไร กรุณาบอกให้ชัดเจนด้วย แต่มันใช้งานไม่ได้ใน Asp.net2.0 มีข้อผิดพลาดดังต่อไปนี้:
ข้อมูลสถานะไม่ถูกต้องสำหรับหน้านี้และอาจเสียหาย
อย่างไรก็ตาม ตอนนั้นฉันไม่เคยพบข้อผิดพลาดดังกล่าวมาก่อน และฉันไม่พบอะไรเลยด้วยการค้นหาใน Google ใช่ฉันไม่รู้ว่าประโยคนั้นผิดหรือเปล่า ฉันซึมเศร้ามาสองวันแล้วและปัญหาก็ไม่สามารถแก้ไขได้โดยธรรมชาติ บันทึกสถานะมุมมองลงในฐานข้อมูลและอ่านจากฐานข้อมูล ฉันไม่พบข้อผิดพลาด ดังนั้นฉันจึงคิดถึงโค้ดครั้งแล้วครั้งเล่า แต่ฉันสับสนเล็กน้อยเกี่ยวกับบรรทัดนั้น ฟิลด์ของ "__VIEWSTATE" ดังนั้นฉันจึงแสดงความคิดเห็นในบรรทัดนี้ และมันใช้งานได้จริง ดังนั้นฉันจึงยังไม่เข้าใจว่าบรรทัดนั้นมีไว้เพื่ออะไร
แน่นอนว่า เรายังสามารถทำหน้าที่ข้างต้นให้สมบูรณ์ได้ด้วยการเขียนคลาสย่อยใหม่ของ PageStatePersister ซึ่งเป็นคลาสใหม่ใน ASP.NET2.0:
namespace PageAdapter
-
ใช้ระบบ;
ใช้ System.IO;
ใช้ System.Security.Permissions;
ใช้ System.Web;
ใช้ System.Web.UI;
[AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
คลาสสาธารณะ DatabasePageStatePersister : PageStatePersister
-
DatabasePageStatePersister สาธารณะ (หน้าเพจ): ฐาน (หน้า)
-
-
// โหลด ViewState และ ControlState
-
การแทนที่สาธารณะเป็นโมฆะ Load()
-
สตริง viewState;
ตัวจัดรูปแบบ IStateFormatter = this.StateFormatter;
DataAccess da = DataAccess ใหม่();
สตริง stateID = base.Page.Request["__VIEWSTATE_KEY"].ToString();
viewState = da.LoadViewState (stateID);
จับคู่ statePair = (คู่) ฟอร์แมตเตอร์ดีซีเรียลไลซ์ (viewState);
ViewState = statePair.First;
ControlState = statePair วินาที;
-
-
// ยังคงมี ViewState และ ControlState ใด ๆ
-
การแทนที่สาธารณะถือเป็นโมฆะบันทึก ()
-
ถ้า (ViewState != null || ControlState != null)
-
ถ้า (Page.Session != null)
-
สตริง viewStateID = "VIEWSTATE#" + base.Page.Session.SessionID.ToString() + "#" + DateTime.Now.Ticks.ToString();
base.Page.ClientScript.RegisterHiddenField("__VIEWSTATE_KEY", viewStateID);
คู่ statePair = คู่ใหม่ (ViewState, ControlState);
ตัวจัดรูปแบบ IStateFormatter = this.StateFormatter;
// ทำให้วัตถุ statePair เป็นอนุกรมเป็นสตริง
string serializedState = formatter.Serialize(statePair);
ViewStateData vsd = ViewStateData ใหม่ ();
vsd.ViewStateID = viewStateID;
vsd.ViewState = สถานะอนุกรม;
DataAccess da = DataAccess ใหม่();
ข้อผิดพลาดสตริง = da.SaveViewState (vsd);
-
อื่น
โยน InvalidOperationException ใหม่ ("เซสชันที่จำเป็นสำหรับ StreamPageStatePersister");
-
-
}
}
จากนั้นคุณสามารถแทนที่คุณสมบัติ PageStatePersister:
protected override PageStatePersister PageStatePersister
-
รับ
-
กลับ DatabasePageStatePersister ใหม่ (หน้า);
-
ไฟล์
ไม่ได้แตกต่างจากฐานข้อมูลมากนัก ฉันแค่พูดถึง ASP.NET2.0 เท่านั้น มันควรจะคล้ายกันใน ASP.NET1.1 แต่ฉันยังไม่ได้เขียนโค้ดสำหรับการดีบัก:
ฉันยังคงใช้วิธีนี้ ของการเขียนคลาสย่อยใหม่ของ PageStatePersister :
namespace StreamPageAdapter
-
ใช้ระบบ;
ใช้ System.IO;
ใช้ System.Security.Permissions;
ใช้ System.Web;
ใช้ System.Web.UI;
//
// StreamPageStatePersister เป็นสถานะมุมมองตัวอย่าง
// กลไกการคงอยู่ที่ยังคงมีมุมมองและการควบคุม
// สถานะบนเว็บเซิร์ฟเวอร์
//
[AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
คลาสสาธารณะ StreamPageStatePersister : PageStatePersister
-
สาธารณะ StreamPageStatePersister (หน้าเพจ): ฐาน (หน้า)
-
-
// โหลด ViewState และ ControlState
//
การแทนที่สาธารณะ void Load()
-
สตรีม stateStream = GetSecureStream ();
// อ่านสตริงสถานะโดยใช้ StateFormatter
เครื่องอ่าน StreamReader = StreamReader ใหม่ (stateStream);
ตัวจัดรูปแบบ IStateFormatter = this.StateFormatter;
string fileContents = reader.ReadToEnd();
// Deserilize ส่งคืนวัตถุคู่ที่ถูกทำให้เป็นอนุกรม
// วิธีการบันทึก
จับคู่ statePair = (คู่) ฟอร์แมตเตอร์ดีซีเรียลไลซ์ (เนื้อหาไฟล์);
ViewState = statePair.First;
ControlState = statePair วินาที;
reader.ปิด();
stateStream.ปิด();
-
-
// ยังคงมี ViewState และ ControlState ใด ๆ
//
การแทนที่สาธารณะถือเป็นโมฆะบันทึก ()
-
ถ้า (ViewState != null || ControlState != null)
-
ถ้า (Page.Session != null)
-
สตรีม stateStream = GetSecureStream ();
นักเขียน StreamWriter = StreamWriter ใหม่ (stateStream);
ตัวจัดรูปแบบ IStateFormatter = this.StateFormatter;
คู่ statePair = คู่ใหม่ (ViewState, ControlState);
// ทำให้วัตถุ statePair เป็นอนุกรมเป็นสตริง
สตริง serializedState = ฟอร์แมตเตอร์ซีเรียลไลซ์ (statePair);
นักเขียนเขียน (serializedState);
นักเขียน.ปิด();
stateStream.ปิด();
-
อื่น
โยน InvalidOperationException ใหม่ ("เซสชันที่จำเป็นสำหรับ StreamPageStatePersister");
-
}
// ส่งคืนสตรีมที่ปลอดภัยสำหรับสภาพแวดล้อมของคุณ
GetSecureStream()
-
เส้นทางสตริง = @"d:a.txt";
FileStream fs = FileStream ใหม่ (เส้นทาง, FileMode.Open, FileAccess.ReadWrite);
กลับ fs;
-
-
}
เพียงแทนที่คุณสมบัติ PageStatePersister:
ป้องกันแทนที่ PageStatePersister PageStatePersister
-
รับ
-
ส่งคืน StreamPageStatePersister ใหม่ (หน้า)
;
จากการแนะนำสั้นๆ ข้างต้น เราควรมีความเข้าใจอยู่บ้าง แต่สิ่งที่เราต้องเข้าใจก็คือ ใน ASP.NET1.1 เราสามารถทำหน้าที่ข้างต้นให้สมบูรณ์ได้โดยการเขียน age.SavePageStateToPersistenceMedium() และ Page.LoadPageStateFromPersistenceMedium() ใหม่เท่านั้น .NET1.1 ใน ASP.NET2.0 นอกเหนือจากนี้ เรายังดำเนินการให้เสร็จสิ้นโดยการเขียนคลาสย่อยใหม่ของ PageStatePersister และแทนที่คุณสมบัติ PageStatePersister ฉันไม่พบความแตกต่างใดๆ แน่นอน หากคุณอ่านเนื้อหาต่อไปนี้ คุณจะเข้าใจว่าการเขียนคลาสย่อยใหม่ของ PageStatePersister ใช้งานได้จริง
การใช้อะแดปเตอร์เพจ
เนื่องจากกลไกการคงอยู่ของสถานะเกี่ยวข้องกับการแสดงผลแบบอะแดปทีฟและฟังก์ชันการทำงานฝั่งไคลเอ็นต์ MyPageAdapter จึงมีไว้เพื่อเปิดใช้งาน DatabasePageStatePersister ของแอปพลิเคชัน ASP.NET สุดท้ายนี้ มีการจัดเตรียมไฟล์ความสามารถของเบราว์เซอร์ (.browser) เพื่อเปิดใช้งาน MyPageAdapter สำหรับคลาสเฉพาะของไคลเอนต์ (ในกรณีนี้คือเว็บเบราว์เซอร์เริ่มต้น)
สำหรับเนื้อหาเหล่านี้ โปรดดูโปรเจ็กต์ PageAdapter ในซอร์สโค้ดที่ฉันให้ไว้ คุณจะเข้าใจหลังจากอ่านมัน
ใช้ System.Security.Permissions;
ใช้ System.Web;
ใช้ System.Web.UI
เนมสเปซ PageAdapter
-
[AspNetHostingPermission (SecurityAction.Demand ระดับ = AspNetHostingPermissionLevel.Minimal)]
MyPageAdapter ระดับสาธารณะ: System.Web.UI.Adapters.PageAdapter
-
การแทนที่สาธารณะ PageStatePersister GetStatePersister()
-
กลับ PageAdapter.DatabasePageStatePersister ใหม่ (หน้า);
-
-
}
สุดท้ายนี้ เพื่อเปิดใช้งานอะแดปเตอร์ MyPageAdapter คุณต้องสร้างไดเร็กทอรีชื่อ App_Browsers ในไดเร็กทอรีรากของแอปพลิเคชัน ASP.NET และรวมไฟล์ .browser ที่มีข้อมูลการกำหนดค่า (อันที่จริงแล้ว สิ่งเหล่านี้จะถูกเพิ่มทั้งหมดเมื่อคุณเพิ่มเข้าไป ไปยังโปรเจ็กต์ ไฟล์ .browser จะถูกทำให้เสร็จสมบูรณ์โดยอัตโนมัติภายใน vs2005 องค์ประกอบ <refID ในไฟล์คอนฟิกูเรชันบ่งชี้ว่าคอนฟิกูเรชันจะแทนที่ค่าที่ระบุโดยเบราว์เซอร์เริ่มต้นในไฟล์คอนฟิกูเรชัน Default.browser ตัวอย่างนี้ใช้ MyPageAdapter สำหรับ ASP หน้าเว็บ .NET (แต่โดยปกติแล้วจะไม่ได้ใช้
อะแดปเตอร์
)
<เบราว์เซอร์ refID="ค่าเริ่มต้น" ><
<ตัวควบคุมอะแดปเตอร์>
<อะแดปเตอร์
controlType = "System.Web.UI.Page"
adapterType = "PageAdapter.MyPageAdapter" />
</ตัวควบคุมอะแดปเตอร์><
</เบราว์เซอร์><
</เบราว์เซอร์><
สามารถดูได้ในโครงการ TestPageAdapter ในซอร์สโค้ด โปรเจ็กต์นี้ใช้เพื่อสาธิตอะแดปเตอร์เพจ
ข้อสรุป
ค่อนข้างง่ายและอาจไม่ชัดเจนมากนัก สำหรับข้อดีและข้อเสียของกลไกการคงอยู่ต่างๆ ฉันยังไม่ได้ทดสอบโดยเฉพาะ และรายการสุดท้าย "ใช้อะแดปเตอร์เพจ" ไม่ใช่กลไกการคงอยู่ แต่ใช้อะแดปเตอร์ ดังนั้นเราจะไม่แทนที่
แอตทริบิวต์ PageStatePersister สำหรับฉันดูเหมือนว่ามันไม่มีประโยชน์มากนัก เนื่องจากเราสามารถใส่การดำเนินการแทนที่ PageStatePersister ในคลาสฐานของเพจได้ และเพจอื่นๆ ทั้งหมดสามารถสืบทอดคลาสพื้นฐานนี้ได้ โค้ดของฉันเป็นอย่างไรบ้าง การใช้อะแดปเตอร์เพจนี้เป็นเรื่องยาก แน่นอนว่าฉันไม่ค่อยรู้อะไรเกี่ยวกับอะแดปเตอร์เพจนี้มากนัก
นอกจากนี้ คำอธิบายสั้น ๆ เกี่ยวกับซอร์สโค้ดของฉัน:
1. โครงการ PageAdapter
DatabasePageStatePersister.cs: คลาสย่อยของคลาส PageStatePersister MyPageAdapter.cs: อะแดปเตอร์เพจ DataAccess.cs และการเข้าถึงฐานข้อมูล ViewSate.cs ที่เป็นของคลาสเสริม
2. โปรเจ็กต์ StreamPageAdapter
คล้ายกับโปรเจ็กต์ด้านบน ดังนั้นฉันจะไม่ลงรายละเอียด
3. โปรเจ็กต์ SaveStateToDatabase
StateInHiddenField.aspx: ทดสอบกลไกการจัดเก็บข้อมูลเริ่มต้น นั่นคือคุณจะเห็นสิ่งที่ยุ่งวุ่นวายมากมายเมื่อคุณดูที่ ไฟล์ต้นฉบับของหน้า
StateInSession.aspx: กลไกการจัดเก็บเป็นเซสชัน
StateInDatabase.aspx: ฐานข้อมูลกลไกการจัดเก็บเป็นชนิดของวิธีการเขียนใหม่ ซึ่งสามารถใช้ได้ โดย asp.net1.1 และ 2.0
StateInDatabase2.aspx: เขียนคลาสย่อยใหม่ของ PageStatePersister และแทนที่คุณสมบัติ PageStatePersister
StateInFile.aspx: บันทึก ViewState ในโฟลเดอร์บนเซิร์ฟเวอร์
4. โครงการ TestPageAdater
ใช้สำหรับการทดสอบและอะแดปเตอร์