Archive

Archive for January, 2009

Cross-page PostBack , PostBackUrl

บทความนี้เป็นบทความต่อเนื่องจาก บทความเรื่อง PostBack ผมได้ทิ้งท้ายไว้ว่า PostBack นั้นใช้งานเฉพาะใน single page และ หากต้องการที่จะทำ Postback ระหว่าง Page นั้นผมก็จะมาพูดในบทความนี้ โชคดีที่เราอ้างอิง ASP.NET 2.0 เพราะว่าเป็น approach ที่เพิ่งจะมีใน version นี่ครับ ส่วนท่านที่ใช้ version ก่อนหน้านี้ รู้สึกว่าจะไม่มีนะครับ ไม่มีไม่ไดหมายความว่าทำไม่ได้นะครับ เขาใช้ Server.Transfer ซึ่งเราก็จะพูดกันใน บทความนี้ด้วยเช่นเดียวกัน

เรามาพูดถึง เรื่อง Cross-Page postbacks กันต่อครับว่า สิ่งที่เป็นส่วนประกอบพื้นฐานที่ทำให้เกิดการทำงานลักษณะนี้ก็คือ property ที่เรียกว่า PostBackUrl ซึ่ง กำหนดโดย interface ที่ชื่อ IButtonControl และใช้งานใน Button controls ต่าง ๆ เช่น ImageButton, LinkButton, และก็ Button

การใช้งาน cross-page posting สามารถทำได้โดย การกำหนด ค่า PostBackUrl ให้อ้างอิงไปยัง webpage ที่เราต้องการ ( web form นะครับ ) เมื่อใดที่ user คลิก ปุ่ม Page จะทำการ posts ไปยัง page ที่กำหนดไว้ที่ PostBackUrl พร้อมกับค่าต่าง ๆ ใน input controls ของ page ปัจจุบัน คงพอจะเห็น ภาพนะครับ เราลองมาดูตัวอย่างกันนะครับ

สมมุติว่า เราสร้าง web form (CrossPage1.aspx)ที่มี text box อยู่สอง text box และ button ซึ่งเราจะกำหนด ให้ post ไปยัง page ที่ชื่อว่า Crosspage2.aspx

.
.

Untitled Page




และใน CrossPage2.aspx.cs สามารถที่ ตรวจสอบการ post จาก CrossPage1.aspx ได้โดยใช้ Page.PreviousPage property ตามตัวอย่าง

.
.
using System.Web.UI.HtmlControls;

public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.PreviousPage != null && Page.PreviousPage.IsCrossPagePostBack)
{
TextBox tFirstName = (TextBox)Page.PreviousPage.FindControl(“txtFirstName”);
TextBox tLastName = (TextBox)Page.PreviousPage.FindControl(“txtLastName”);
Label1.Text = “Hello ” + tFirstName.Text + ” ” + tLastName.Text;
}
}
}

จาก ตัวอย่าง code นั้นสามารถอธิบายได้ว่า หากมีการ post มาจาก page ก่อนหน้า ( ซึ่งค่า PerviousPage.IsCrossPagePostBack จะเท่ากับ true และ PreviousPage นั้จะต้องไม่เป็น null ด้วย ) และแสดงข้อมูลที่กรอก ใน TextBox txtFirstName และ txtLastName เป็นตัวอย่าง ง่าย ๆ สามารถนำไปประยุกค์ใช้ได้เลย นะครับ

มาพิจารณาตรงนี้เพิ่มเติมสักนิดนะครับเรื่องวิธีการส่งค่าระหว่าง Page หรือวิธีการทำเพื่อให้สามารถ ส่งค่าระหว่าง page ได้ วิธีแรกก็คือวิธีที่แสดงไว้ในตัวอย่างแรก นะครับเราสามารถที่จะใช้ FindControl method เพื่อตรวจสอบหา control id ที่กำหนด ซึ่งเป็นวิธีที่นิยมใช้กัน

มีอีกวิธีหนึ่ง คือการกำหนด previous page ใน PreviousPageType directive ใน page ที่จะรับข้อมูลในตัวอย่างของเราก็คือใน CrossPage2.aspx วิธีนี้จะทำให้เราสามารถเข้าถึง public member ของ web form ได้นะครับ โดยไม่ต้องทำการ casting ดังจะแสดงให้ดู
เราจะทำการเพิ่ม property ให้กับ CrossPage1.aspx.cs ดังนี้นะครับ

protected void Page_Load(object sender, EventArgs e)
{
}
public string FirstName
{
get { return (!string.IsNullOrEmpty(txtFirstName.Text)) ? txtFirstName.Text : string.Empty; }
}
public string LastName
{
get { return (!string.IsNullOrEmpty(txtLastName.Text)) ? txtLastName.Text : string.Empty; }
}

และที่ CrossPage2.aspx เราจะเพิ่ม PreviousPageType ต่อจาก Page directive ดังนี้

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="CrossPage2.aspx.cs" Inherits="Default2" %>
<%@ PreviousPageType VirtualPath="CrossPage1.aspx" %>
.
.

ซึ่งจะทำให้เราสามารถอ้างอิงได้ ดังนี้

.
.
if (Page.PreviousPage != null && Page.PreviousPage.IsCrossPagePostBack)
{
string lFirstName = PreviousPage.FirstName;
string lLastName = PreviousPage.LastName;
Label1.Text = “Hello ” + lFirstName + ” ” + lLastName;
}
.
.

ครับ พอจะเห็นภาพนะครับ วิธีที่สองนี้เป็นวิธีที่ดีอีกเหมือนกันแต่ ข้อด้อยก็คือ มัน specific มากเกินไปครับ ก็คือมันจะต้องเป็นการเรียกผ่านมาจาก CrossPage1.aspx เท่านั้น ในบ้างเหตุการเราอาจะต้องการ ให้ page หนึ่งสามารถรับค่าจาก page ต่าง ๆ กันได้ ข้อดีก็คือมันสามารถอ้างอิง public member ได้เลยเพราะมันเป็น strongly type access

คงพอจะได้ concept นะครับ ที่การทำ cross-page postback นี่สามารถทำได้อีก วิธีหนึ่งโดยใช้ Server.transfer ผมจะเอาไว้พูดในบทความถัดไปนะครับ เพราะเริ่ม เมื่อยแล้ว สำหรับบทความนี้ใครสงสัยอะไรก็ ถามกันได้นะครับ หรือจะ mail มาถามก็ได้ s_teerapong2000@yahoo.com 🙂

The Postback Architecture , การทำงาน ของ Postback

บทความนี้ผมจะขอพูดถึง Postback เพื่อให้กระจ่างสำหรับ โปรแกรมเมอร์ มือใหม่ที่ยังไม่เข้าใจการทำงานของ Page event สักเท่าไรนัก ทำให้ไม่สามารถเขียน code ให้เป็นไปตามความเข้าใจได้ ดังนั้นสิ่งแรก ที่เราต้องเข้าใจคือการทำงาน ขอ Postback

ปัญหาสำคัญที่ โปรแกรมเมอร์มือใหม่เจอก็คือ event Page_Load นั้นจะเกิดขึ้นทุกครั้ง แม้แต่การ click ปุ่ม page_load มันก็ยัง เกิดขึ้น ปัญหาก็คือบางครั้งเราต้องการที่จะ เชตค่าตั้งต้นให้กับตัวแปรบางอย่าง เฉพาะเมื่อมีการ load page นั้นครั้งแรก เท่านั้น หรือในบางกรณีเราต้องการให้มีการเปลี่ยนแปลงค่าเฉพาะเมื่อมีการ click ปุ่มเท่านั้น

ลองพิจารณาตัวอย่าง นี้กันนะครับ สมมติว่าเราสร้าง form ที่มีลักษณะดังรูปนะครับ

postback1

จากตัวอย่าง เราต้องการให้ Label1 นั้นแสดงข้อมูลใน TextBox1 ทุกครั้งเมื่อมีการ Click ปุ่ม Button1 และ ครั้งแรกที่ load page นี้ให้แสดง ข้อความ “Enter some text and press button” ที่ label

ซึ่งเราจะสามารถ ใส่ code ได้ดังนี้

..
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
Label1.Text = “You enter ” + TextBox1.Text;
}
else
{
Label1.Text = “You enter some text and press command ! “;
}
}

}

สังเกตที่ Page.IsPostBack property นะครับ เราใช้ คุณสมบัตินี้เป็น condition สำหรับแยกการทำงานระหว่าง การ load ครั้งแรก ( กรณีที่ IsPostBack เป็น เท็จ หรือ false ) และการ PostBack ซึ่งเกิดจากการ ที่เรา click ปุ่ม ( กรณีที่ IsPostBack เป็นจริง หรือ true ) ซึ่งเมื่อทำการ run code นี้ก็จะได้ผลตามต้องการ

How it work
การทำงานก็อย่างที่ได้กล่าวไปแล้ว นะครับ ว่า IsPostBack จะเป็นตัวที่ช่วยให้เราจำแนกได้ว่า ใน event Page_load ขณะนั้นเป็น การ PostBack หรือไม่ นั้นก็หมายถึงว่า User ได้มีการ Click ปุ่ม หรือไม่ หาก เป็นการ Click ปุ่ม IsPostBack เป็นจริง หากเป็นการ load Page นั้นครั้งแรก IsPostBack ก็จะเป็น false นั่นเอง

สิ่งที่ต้อง เข้าใจและจดจำไว้อีก ประเด็นหนึ่งก็คือ postback นั้น ออกแบบมาใช้กับ การทำงาน Page ใด ๆ หรือ Single page นะครับ หมายความว่า IsPostBack จะถูก Reset ใหม่เมื่อ เราเรียกไปยัง Page อื่น หรือจาก Page หนึ่งไปยังอีก Page หนึ่ง เราสามารถสรุปได้เป็นตารางดังนี้

postback2

ครับ ผมคิดว่า เรื่องนี้ เป็น Basic ที่เราจะต้องทำความเข้าใจ ให้ดีก่อนที่เราจะสร้าง application จริงนะครับ เพราะเราจะต้องใช้ มันไปตลอด จริงแล้วมันคงยังมีคำถามค้างคาใจอยู่อีก ว่าเราสามารถจะทำการ postback ระหว่าง page ได้หรือไม่ ตอบว่าได้ครับ แล้ว ผมจะเอามาพูดต่อไปนะครับ สำหรับ บทความนี้มันเป็นส่วนหนึ่งในหนังสือ เล่มนี้นะครับ Beginning ASP.NET 2.0 with C# ไปหาอ่านเพิ่มเติมกันได้ นะครับ

Categories: ASP.NET, Web form Tags:

View State , ASP.NET State Management

HTTP นั้นเป็น protocol ประเภทที่เรียกว่า stateless  ขึ้น มาแบบนี้ programmer ที่ทำงานด้านนี้ทราบดีอยู่แล้ว แต่สำหรับมือใหม่ หรือเพิ่งเข้ามาจับงานประเภท web base programming ละก็จะต้องทำความเข้าใจกันซะก่อนเป็นเบื่องต้น และเข้าใจมาก ๆ ในเบื้องกลาง และเข้าใจสุด ๆ ในเบื้องปลาย ฮะ ฮะ
Stateless เป็นอย่างไรนะหรือครับลักษณะก็คือ ทุกครั้งที่มีการ request ไปยัง server ( หมายถึง webbrowser นะครับ ) เสร็จแล้วก็จะ disconnect เลยนะครับไม่มีการ คง connection ไว้ เพราะฉะนั้น จะไม่มีการคงอะไรไว้หรือรักษาอะไรไว้เลยระหว่าง สอง connection แบบนี้แหละครับที่เรียกว่า stateless เหตุผลของ architecture นี้ก็คือ เพื่อให้ server สามารถรองรับการ request พร้อม ๆ กัน หลาย ๆ พัน หลาย ๆ หมื่น client โดยที่ไม่เกิด run out of memory นะครับ แต่ปัญหา ของมันก็คือ อืม เราไม่เรียกว่าปัญหา เรียกว่าข้อด้อยของมันดีกว่า ข้อด้อยของมันก็คือ programmer จะต้องหา techniques อื่นเพื่อรักษาข้อมูลระหว่างที่มีการ request และสามารถดึงข้อมูลเหล่านั้นมาใช้งานได้ตามต้องการนั่นเอง

ที่เกรินมาทั้งหมดนี้ก็ เพราะว่า ผมจะหาข้อมูลและเขียนเกี่ยวกับ State Management ในหลาย ๆ ระดับ มาเล่าสู่กันฟัง และก็จะรวมถึง technique การส่งผ่านส่งผ่านข้อมูลจาก page หนึ่งไปยังอีก page ด้วย ดังนั้นในหัวข้อเหล่านี้มันก็คง จะมีหลาย ๆ ตอนอยู่นะครับ ถ้าพลังมีมาก ผมคง ให้รายละเอียดได้ทั้งหมด

View State

View state เห็นจะเป็นหัวข้อแรกที่ผมเลือก ที่จะพูดถึงเพราะ View state นี้เราใช้ในการรักษาข้อมูล ภายใต้กรอบการทำงาน page เดียวเท่านั้น ( ASP.NET web controls ใช้ View State เป็นพื้นฐานอยู่แล้ว ) ซึ่ง View state มันจะทำให้เรารักษาข้อมูลระหว่าง postbacks ได้ ( เหตุการณ์ที่จะทำให้เกิด postback เช่น การ click ปุ่มเป็นต้น )
Page object มี property ที่ชื่อว่า ViewState เป็นตัวช่วยให้เราสามารถที่จะเพิ่มข้อมูลเข้าไปใน View State Collection ได้ และ ข้อมูลที่เราสามารถที่จะเก็บลงใน view state ก็เป็นได้ทั้ง simple data types และ ก็ objects ที่เราสร้างขึ้นมา
ต่อไปเรามาดูการใช้งาน View State กันนะครับ เนื่อง จาก View State นั้นมีรูแบบ ที่เรียกว่า dictionary collection ก็หมายถึงว่าข้อมูลแต่ละตัวจะถูกอ้างอิงด้วย string name ที่แตกต่างกัน เช่น

ViewState[“Counter”] = 1;

นั่นเป็นการ เก็บ 1 ลงใน ViewState Collection และอ้าอิงด้วยชื่อที่มีความหมาย คือ Counter ตรงนี้สำคัญนะครับ ถ้า Counter ยังไม่เคยปรากฏอยู่ใน ViewState collection เลย มันก็จะเพิ่ม Counter เข้าไปและเก็บค่า 1 แต่ถ้า Counter มีอยู่แล้ว มันจะแทนที่ค่าเดิมด้วย 1 นะครับ

การ retrieve ข้อมูล เราก็อ้าอิง ด้วยชื่อ Counter ในลักษณะเดียวกับการ บันทึกข้อมูลงไป ( Counter เราเรียกว่าเป็น Key name ) และเราก็ต้องทำ casting ด้วย data type ที่เหมาะสมนะครับ เพราะการเก็บค่าเข้าเป็นใน View state collection นั้นมักจะถูก ทำให้เป็น object โดยอัตโนมัติ ( กรณีที่พวก simple data type เช่น integer ) ดังนั้นต้อง casting ก่อนเพื่อให้ได้ข้อมูลที่ถูกต้องและนำไปใช้งาน ต่อไปเป็นตัวอย่างของ code แสดงการ retrieve ข้อมูลจาก View State collection

int counter ;
if (ViewState[“Counter”] != null)
{
Counter (int)ViewState[“Counter”];
}

ถ้าเรา พยายามที่จะ retrieve ข้อมูลซึ่งไม่มีเก็บอยู่ใน หรือ ไม่ปรากฏอยู่ ใน Collection เราจะได้ NullReferenceException มาแทน ใน code ก็เลยต้องทำการ ตรวจสอบซะก่อนว่า มีข้อมูลปรากฏอยู่หรือไม่ ถือว่าเป็นหลักปฏิบัติโดยทั่วไป นะครับ
จากตัวอย่างที่ผ่านมา เราสามารถประยุกค์ใช้กับ Data types ชนิดอื่นได้ (Simple data types) นอกจากนี้เรายังสามารถที่จะบันทึก ข้อมูลที่เป็น object ลงใน Veiw State ได้ด้วยเช่นกัน แต่การบันทึกข้อมูล objects ลง View State นั้น Object จะต้องเป็น Object ที่ประกาศให้สามารถ แปลงให้เป็น bytes  stream ได้ หรือ ที่เรียกว่า serialization ครับ การทำก็ไม่ได้เป็นเรื่องยากอะไรครับ แค่เพิ่ม ‘Serializable’ attribute ไว้ที่ การประกาศ class  ดังตัวอย่าง

[Serializable]
public class Student
{
public string firstName;
public string lastName;

public Student(string fName, string lName)
{
firstName = fName;
lastName = lName;
}
}

การเก็บค่าลงใน View State

// Storing a student in view state.
Student stud = new Student(“John”, “Doe”);
ViewState[“CurrentStudent”] = stud;

และการดึงข้อมูลออกมาใช้งาน

// Retrieve a student from view state.
Student stud = (Student) ViewState[“CurrentCustomer”];

อย่าลืมนะครับ เวลาเราดึงข้อมูลจาก View Sate จะต้องทำการ casting ให้เป็น Datatype เดียวกับที่เรา ใส่ลงไปนะครับ ในเรื่อง serializable นั้น มีข้อกำหนดดังนี้นะครับ

  • class จะต้องกำกับด้วย serializable attribute
  • derive ก็จะต้อง เป็น serializable ด้วย
  • ตัวแปร private ของ class ก็จะต้องเป็น serializable หรือ ถ้ามี none serializable ก็จะต้องกำกับ ด้วย [none serializable] attribute

ตัวอย่างการใช้งาน สมมติว่าเราจะทำ PostBack counter ก็คือเราจะทำการเพิ่มค่าทีละ 1 ทุกครั้งที่มีการ click ปุ่มนะครับ ลองมาดูกันว่าเป็นอย่างไร

อันดับแรกเรา สร้าง page ใส่ control ดังต่อไปนี้

และที่ code เป็นอย่างนี้ครับ อันดับแรกเป็นของ Page load event

protected void Page_Load(object sender, System.EventArgs e)
{
//First we check if the page is loaded for the first time,
if (!IsPostBack)
{
ViewState[“PostBackCounter”] = 0;
}
//Now, we assign the variable value in the text box
int counter = (int)ViewState[“PostBackCounter”];
Label1.Text = counter.ToString();
}

ถัดมาเป็น ของ OnClick ของ Button1

protected void Button1_Click(object sender, System.EventArgs e)
{
int oldCount = (int)ViewState[“PostBackCounter”];
int newCount = oldCount + 1;
//First, we assign this new value to the label
Label1.Text = newCount.ToString();
//Secondly, we replace the old value of the view state so that the new value is read the next //time
ViewState[“PostBackCounter”] = newCount;
}

ครับ จาก code จะเห็นว่า ทุกครั้งที่มีการ Click ปุ่ม จะทำการเพิ่มค่าให้ PostBackCounter ทีละหนึ่งนะครับ แต่ครั้งแรกที่ load page นี้จะทำการ set ค่าไปที่ 0
ครับที่กล่าวมาและตัวอย่าง ต่าง ก็คงพอที่จะได้ แนวความคิดการใช้งาน View state บ้าง ไม่มากก็น้อยนะครับ