TextBox.Readonly=true; האומנם?

21 בספטמבר 2008

אין תגובות

טעות נפוצה שאני נתקל כאשר אני עובר על קוד של תוכניתנים אחרים זה בלבול בנושא תכונת ה-ReadOnly של TextBox. מאיזהשהי סיבה, תוכניתנים יוצאים מנקודת הנחה שברגע שהם כתבו ReadOnly אז המשתמש באמת לא יוכל לערוך את התוכן של תיבת הטקסט.

תיכננתי ניסוי קטן שיבדוק את הנושא. ניצור דף עם הפריטים הבאים:
1. תיבת טקסט – פקד TextBox. התוכנה ReadOnly תהיה True, והתכונה Text תהיה על "Original Text".
2. כפתור – כפתור פשוט שיגרום ל-PostBack.
3.סקריפט ג'אווה – הסקריפט ייגש לתגית ה-<input> בצד לקוח וינסה לשנות את הערך שלה ל-"Not original Value!". הסקריפט ירוץ בטעינת הדף.
4. Label – לתוכה נדפיס את הערכים של ה-TextBox שלנו בכל טעינה של הדף.

1. נפתח טופס חדש. נשרטט את הכפתור ונקבל את ה-Design HTML הבא:

<asp:Button id="btnTesting" style="Z-INDEX: 102; LEFT: 520px; POSITION: absolute; TOP: 288px" runat="server" Width="184px" Height="56px" Text="Button"></asp:Button>

2. נשרטט את תיבת הטקסט ונקבע את התכונות אשר הזוכרו לעיל ונקבל את ה-Design HTML הבא:

   <asp:TextBox id="tbxTest" style="Z-INDEX: 101; LEFT: 536px; POSITION: absolute; TOP: 216px" runat="server" Width="136px" Height="24px" ReadOnly="True"> Original Text </asp:TextBox>

3. נוסיף פונקציה בג'אווה סקריפט שתחפש את תיבת הטקסט שלנו ותשנה את הערך שלה:

  <script type="text/javascript">
   function testing()
   {
    tbxTest = document.getElementById("tbxTest");
    tbxTest.value = "Not original Value!";
   }
  </script>

הקוד לעיל מאוד פשוט, כל מה שהוא עושה זה למצוא אלמנטים בקוד עם השם של תיבת הטקסט שלנו ומשנה את ערך תיבת הטקסט. כמו כן נרשום את האירוע לOnLoad בתגית ה-<body>:

<body MS_POSITIONING="GridLayout" onload="testing();">
 

4. נוסיף Label בצד שרת בשם lblTesting:

<asp:Label id="lblTesting" style="Z-INDEX: 103; LEFT: 488px; POSITION: absolute; TOP: 48px" runat="server" Height="128px" Width="264px"></asp:Label>

נוסיף באירוע ה-Page_load את הטקסט שיכניס את ערך תיבת הטקסט לתוך ה-Label:

  private void Page_Load(object sender, System.EventArgs e)
  {
   // Add TextBox value to Label
   lblTesting.Text += "TextBox Testing: " + tbxTest.Text + "<br>";
  }

כעת הטופס שלנו יראה בתצוגת Design כמו בתמונה הבאה:

image

לפני שאנחנו מריצים את הטופס הזה בואו נחשוב שנייה מה עשינו ומה התוצאות האפשריות. יצרנו תיבת טקסט, יצרנו פונקציה בלקוח שמשנה את ערך תיבת הטקס וכפתור שיצור PostBack לשרת.

אם ReadOnly=true בפקד TextBox נועל את הערך מצד השרת נצפה לראות את הערך המקורי של תיבת הטקסט, ללא קשר לאיזה שינויים בוצעו בצד לקוח.

לעומת זאת, אם נראה ב-Label לאחר ה-PostBack את הערך החדש שנתנו לו בפונקציית הג'אווה סקריפט הוכחנו ש-Readonly=true בפקד TextBox אינו שומר על הערך בצד שרת. למעשה אם כך המצב מה שיתבצע הוא שהשרת שולח את תיבת הטקס כמו כל תיבה רגילה וקורא בחזרה את ערכה כמו כל תיבה רגילה.

נריץ את הטופס בפעם הראשונה ונקבל את המסך שנראה כמו בתמונה הבאה:

image

בצד הלקוח כבר השתנה ערך תיבת הטקסט. נלחץ על הכפתור, נגרום ל-PostBack ונקבל את התמונה הבאה:

image

מה שקיבלנו זה שקביעת TextBox עם תכונת Readonly=true למעשה אינו מגן על הערך מפני שינוי בצד לקוח ולאחר מכן בצד שרת. השרת לוקח את ערך תיבת הטקסט מתוך הנתונים אשר הלקוח שולח לשרת ולא מתוך נתוני השרת.

חשוב לזכור, לקבוע Readonly=true לתיבת טקסט הוא אפקט גרפי-ממשקי בלבד. ללא שום קשר ל-Validation ולכן כל שימוש בנתונים המופיעים בתיבות טקסט אלו אינו מאובטח ונוגד את ההיגיון העסקי שלנו.

אם אתם באמת רוצים להציג תיבות טקסט כאלו בשביל ממשק המשתמש, זה בסדר. אבל הנתונים האלו בלתי-אמינים בעליל לשימוש בהיגיון העסקי של האפליקציה שלנו. 

כרגע זה היינו אנחנו (המפתחים של התוכנה) עם ג'אווה סקריפט, אבל מחר זה יכול להיות האקר ששומר את הדף על המחשב ועורך אותו. לא הייתם רוצים שהאקר יתחיל לערוך לכם את כל המסד לפי רצונו שכל מה שמגביל אותו זה להחדיר JavaScript לדף שגם ככה נמצא על המחשב שלו?

לסיכום ולחזרה בפעם שלישית, אין להשתמש ב-TextBox עם readonly=true במשהו כיותר מאפקט בממשק צד לקוח. הם אינם מאובטחים והמידע בהם נתון לשינויים בלתי רצויים. ואם כבר זה סה"כ אפקט בצד לקוח בכלל לא צריך לזה פקד. תחשבו לשנייה שאין שום סיבה שזה לא יהיה Literal control (פקד שאנחנו נכתוב לתוכו את ה-HTML שהוא יציג).

 

לקריאה נוספת: TextBox.ReadOnly Property, ב-MSDN

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *