วันนี้ฉันได้รับอีเมลและถูกถามว่าทำไม UpdatePanel ถึงสร้างปัญหาหากใช้ร่วมกับ UrlRewrite ฉันไม่ได้จริงจังกับมันในตอนแรก เพราะว่าฉันเคยใช้ UpdatePanel ใน UrlRewrite มาก่อนด้วย และก็ไม่มีปัญหาอะไร อย่างไรก็ตามหลังจากได้รับโค้ดแพ็คเกจจากอีกฝ่ายแล้ว ฉันพบว่าปัญหาเกิดขึ้นอีกแน่นอน ถ้าฉันเข้าถึงหน้าเป้าหมายโดยตรงก็คงไม่มีปัญหา เนื่องจากตอนนั้นผมอยู่ในบริษัทและไม่ได้ศึกษาสาเหตุของข้อผิดพลาดอย่างละเอียด ระหว่างทางกลับบ้าน ฉันจำลองกระบวนการใช้งาน UpdatePanel ซ้ำแล้วซ้ำอีกในใจ แต่ก็ไม่ได้สังเกตเห็นสิ่งผิดปกติใดๆ ในที่สุดฉันก็ช่วยตัวเองไม่ได้ ฉันเปิดแล็ปท็อปขณะนั่งอยู่บนรถบัสและค้นหาปัญหาอย่างระมัดระวัง รถบัสสั่นแรงมาก แต่โชคดีที่ฉันพบปัญหาก่อนที่จะอาเจียนออกมาในที่สุด
การจำลองปัญหา:
ตอนนี้ฉันจะจำลองปัญหาอีกครั้ง UrlRewriteModule ของ NBear ถูกใช้ในโค้ดต้นฉบับ เพื่อความเรียบง่าย ฉันจึงใช้วิธี UrlRewrite ที่ใช้บ่อยที่สุดเพื่อให้ได้ผลแบบเดียวกัน โดยพยายามหลีกเลี่ยงเพื่อนบางคน (รวมถึงฉันด้วย) ที่ไม่คุ้นเคยกับ NBear และขัดขวางความเข้าใจในบทความ เนื้อหา.
ขั้นแรก สร้างเว็บไซต์ที่เปิดใช้งาน ASP.NET AJAX ใหม่ สร้างไฟล์ ~/SubFolder/Target.aspx โดยมีเนื้อหาดังต่อไปนี้:
~/SubFolder/Target.aspx
<html xmlns=" http://www.w3.org/1999/xhtml " >
<หัว runat="เซิร์ฟเวอร์">
<title>หน้าเป้าหมาย</title>
</หัว>
<ร่างกาย>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="เซิร์ฟเวอร์">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="เซิร์ฟเวอร์">
<เทมเพลตเนื้อหา>
<%= DateTime.Now.ToString() %>
<asp:Button ID="Button1" runat="server" Text="รีเฟรช" />
</เทมเพลตเนื้อหา>
</asp:UpdatePanel>
</แบบฟอร์ม>
</ร่างกาย>
</html>
จากนั้นสร้าง Global.asax จัดเตรียมเมธอด Application_BeginRequest และใช้ Url Rewrite ในนั้น ดังนี้:
เมธอด Application_BeginRequest ใน Global.asax
เป็นโมฆะ Application_BeginRequest (ผู้ส่งวัตถุ EventArgs e)
-
บริบท HttpContext = (ผู้ส่งเป็น HttpApplication).บริบท;
ถ้า (context.Request.Path.Contains("Source.aspx"))
-
context.RewritePath("โฟลเดอร์ย่อย/Target.aspx", false);
-
-
ด้วยวิธีนี้ เมื่อเราเข้าถึงไฟล์ ~/Source.aspx มันจะถูกเขียนใหม่เป็น ~/SubFolder/Target.aspx เปิดหน้า และทุกอย่างเป็นปกติ:
หลังจากคลิกปุ่มรีเฟรช เวลาจะถูกอัพเดต จากนั้นเมื่อเราคลิกปุ่มอีกครั้ง เกิดข้อผิดพลาด: "Sys.WebForms.PageRequestManagerServerErrorException: เกิดข้อผิดพลาดที่ไม่รู้จักขณะประมวลผลคำขอบนเซิร์ฟเวอร์ รหัสสถานะที่ส่งคืนจากเซิร์ฟเวอร์คือ: 12031"
การวิเคราะห์ปัญหา:
สาเหตุของปัญหานี้คือ Url Rewrite อัปเดตที่อยู่ที่ส่งโดยแบบฟอร์ม และ UpdatePanel สะท้อนถึงการเปลี่ยนแปลงในที่อยู่ในเพจ
เมื่อเราเปิดเพจเป็นครั้งแรกเราจะเห็นว่าการทำงานขององค์ประกอบ <form /> ในไฟล์ต้นฉบับของเพจนั้นไม่ใช่ Source.aspx ที่เราเข้าถึงอีกต่อไป แต่เป็นไฟล์เป้าหมายหลังจาก Url Rewrite:
การดำเนินการ ขององค์ประกอบแบบฟอร์มคือหน้าเป้าหมาย
-
<ชื่อฟอร์ม = "form1" method = "โพสต์" action = "โฟลเดอร์ย่อย/Target.aspx" id = "form1">
-
</แบบฟอร์ม>
...
โชคดีที่เราใช้การเรนเดอร์บางส่วน ตราบใดที่ "เป้าหมาย" ถูกต้อง UpdatePanel ยังสามารถส่งและรับข้อมูลได้อย่างถูกต้อง จากนั้นอัปเดตเพจ ดังนั้นหลังจากคลิกปุ่มรีเฟรช เพจก็จะได้รับการอัปเดตอย่างถูกต้อง อย่างไรก็ตาม การทำงานขององค์ประกอบแบบฟอร์มของเราก็เปลี่ยนไปเช่นกัน ซึ่งสามารถเห็นได้อย่างรวดเร็วโดยใช้ Web Development Helper และ IE Dev Toolbar:
เนื่องจากเราเข้าถึงโดยตรง ~/SubFolder/Target.aspx เมื่อดำเนินการ PostBack แบบอะซิงโครนัส ค่าการกระทำของออบเจ็กต์ Form ที่สร้างขึ้นคือ Target.aspx ด้วยเหตุนี้ UpdatePanel จึงปรับเปลี่ยนการกระทำขององค์ประกอบแบบฟอร์มไคลเอ็นต์อย่างขยันขันแข็ง สิ่งนี้จะทำให้เราสามารถเข้าถึงเพจที่ไม่มีอยู่เมื่อเราส่งอีกครั้ง และข้อผิดพลาดเป็นสิ่งที่หลีกเลี่ยงไม่ได้
แก้ไขปัญหา:
เมื่อคุณค้นพบปัญหาแล้ว คุณจะสามารถแก้ไขได้อย่างง่ายดายโดยธรรมชาติ เราจำเป็นต้องตอบสนองต่อเหตุการณ์การโหลดของ Sys.Application เท่านั้น มันจะถูกทริกเกอร์เมื่อมีการโหลดเพจเป็นครั้งแรกและหลังจากการเรนเดอร์บางส่วนแต่ละครั้ง ในขณะนี้ เราสามารถแก้ไขแอตทริบิวต์การกระทำขององค์ประกอบแบบฟอร์มในเพจได้ ดังต่อไปนี้:
เหตุการณ์โหลด Sys.Application ที่สอดคล้องกัน
Sys.Application.add_load (ฟังก์ชัน ()
-
แบบฟอร์ม var = Sys.WebForms.PageRequestManager.getInstance()._form;
form._initialAction = form.action = window.location.href;
-
เหตุใดองค์ประกอบแบบฟอร์มในเพจจึงควรได้รับในลักษณะนี้ _initialAction คืออะไร และเหตุใดจึงควรตั้งค่า องค์ประกอบดังกล่าวเกี่ยวข้องกับการนำ UpdatePanel ไปใช้ ดังนั้น ฉันจะไม่อธิบายไว้ที่นี่ ตราบใดที่มีการวางโค้ดเล็กๆ บนหน้า ปัญหานี้ก็จะหมดไป
คำถามเชิงลึก:
สาเหตุของปัญหานี้จริงๆ แล้วหลังจากเขียน Url Rewrite การทำงานขององค์ประกอบแบบฟอร์มไม่ใช่ที่อยู่ที่ร้องขอโดยไคลเอ็นต์ แต่เป็นที่อยู่เป้าหมายของ Url Rewrite หากเราไม่ใช้ Partial Rendering แต่ใช้ PostBack แบบดั้งเดิมที่สุด แม้ว่าฟังก์ชันเพจจะไม่ได้รับความเสียหาย แต่หลังจาก PostBack ผู้ใช้จะพบว่าเนื้อหาของแถบที่อยู่มีการเปลี่ยนแปลงและกลายเป็นที่อยู่เป้าหมายโดยตรง นี่ไม่ใช่ผลลัพธ์ที่เราต้องการเห็น ตอนนี้มันถูกเขียนใหม่แล้ว มาเขียนใหม่จนจบ แน่นอนว่าเรายังคงสามารถใช้วิธีการที่กล่าวมาข้างต้น และใช้ JavaScript เพื่อแก้ไขการกระทำขององค์ประกอบแบบฟอร์มได้ แต่วิธีนี้ไม่ "สวยงาม" เพียงพอ และผู้ใช้ยังสามารถดูที่อยู่เป้าหมายของการเขียน Url ของเราใหม่จากซอร์ส HTML ไฟล์ไม่ใช่เหรอ?
คงจะดีมากถ้าเราสามารถตั้งค่าการกระทำของแบบฟอร์มบนฝั่งเซิร์ฟเวอร์ได้ แต่น่าเสียดายที่คลาส System.Web.UI.HtmlControls.HtmlForm ไม่อนุญาตให้เราทำสิ่งนี้ แต่โชคดีที่เราใช้ ASP.NET และเราใช้โมเดลการเขียนโปรแกรมเชิงวัตถุ ดังนั้นเราจึง "สืบทอด" System.Web.UI.HtmlControls.HtmlForm และใช้การควบคุมแบบฟอร์มของเราเอง:
สืบทอดคลาส HtmlForm เพื่อใช้งาน From ของเราเอง
เนมสเปซ ActionlessForm {
แบบฟอร์มคลาสสาธารณะ: System.Web.UI.HtmlControls.HtmlForm
-
ป้องกันแทนที่เป็นโมฆะ RenderAttributes (ผู้เขียน HtmlTextWriter)
-
writer.WriteAttribute("ชื่อ", this.Name);
base.Attributes.Remove("ชื่อ");
writer.WriteAttribute("วิธีการ", this.Method);
base.Attributes.Remove("วิธีการ");
this.Attributes.Render (ผู้เขียน);
base.Attributes.Remove("การกระทำ");
ถ้า (base.ID != null)
Writer.WriteAttribute("id", base.ClientID);
-
-
-
จากนั้นเราก็สามารถนำไปใช้ในเพจได้ แน่นอนก่อนหน้านั้นเราต้องลงทะเบียนในหน้า (หรือ Web.config):
ใช้แบบฟอร์มที่เรานำไปใช้เอง
<%@ ลงทะเบียน TagPrefix="skm" Namespace="ActionlessForm"
แอสเซมบลี = ActionlessForm %>
-
<skm:Form id="Form1" method="post" runat="server">
-
</skm:แบบฟอร์ม>
-
ณ จุดนี้ เราไม่จำเป็นต้องเขียน JavaScript ที่ "ฉลาด" ในหน้าอีกต่อไป ปัญหาการดำเนินการขององค์ประกอบแบบฟอร์มหลังจากแก้ไข Url Rewrite แล้ว
("คำถามเชิงลึก" อ้างถึงส่วนหนึ่งของบทความก่อนหน้าใน MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp )
http://www.cnblogs.com/JeffreyZhao/archive/2006/12/27/updatepanel_with_url_rewrite.html