שאלה:
אני עובדת עם Microsoft AJAX ומחזירה מהשרת ללקוח Enumים. הבעיה היא שבמקום להעביר ללקוח את הטקסט של ה-Enum אנחנו מקבלים את האינדקס של הערך הנבחר.
אפשר לשנות את ההתנהגות הזו שיעביר את הטקסט של הערך? אולי בצמוד לאינדקס?
תשובה:
בואו נראה דוגמה לבעיה לפני שנפתור אותה.
נתקין Microsoft AJAX ו-ASP.Net Futures אחרי שהורדנו אותם מכאן - http://ajax.asp.net/downloads/default.aspx?tabid=47.
ניצור אתר Microsoft AJAX CTP Enabled חדש.
נכתוב Enum חדש בדוט נט.
ניצור דף בסיסי שמשתמש ב-PageMethods כדי להחזיר ערכים ללקוח.
יש לנו ScriptManager בדף עם EnablePageMethods=True כדי שנוכל לקרוא למתודות public static שיושבות ב-code behind של הדף מתוך ג'אווה סקריפט.
שהטופס עולה אנחנו קוראים לפונקציה בג'אווה סקריפט בשם UseEnum שמריצה מתודה (גם באנגלית: Method) צד-שרת בשם ReturnMyEnum והערך שהמתודה מחזירה מודפס באמצעות alert.
נראה את ReturnMyEnum.
נריץ את הדף ומה שנקבל זה:
לא שימושי מדי, הרי בצד לקוח - אין לאפס הזה שום משמעות עבורנו.
נתחיל מהפתרון הפשוט והלוקאלי ביותר.
אם רק רצינו להחזיר את הטקסט "First" פשוט נשנה את ערך ההחזרה באמצעות ToString.
ושנריץ את הדף נקבל:
יש עם הפתרון הזה כמה בעיות:
1. כמות השינוי שנדרשת באפליקציה שלנו. ברור ששינוי בצד-לקוח ידרש לא משנה מה יהיה הפתרון שלנו, אבל עם הפתרון הזה נצטרך לערוך את כל המתודות צד-שרת שיחזירו string ולא-enum. זה לא מעט עבודה בפרוייקט קיים.
2. המילה "First" לא מייצגת שום דבר, היא רק מחרוזת. היא לא חלק מאיזה Enum גדול יותר.
פתרון נוסף, יפתור את הבעיה המקורית ובעיה מספר 2 שהעלנו.
נמשיך להחזיר ללקוח את האינדקס הנבחר של ה-Enum, אבל נשתמש ב-Microsoft AJAX Javascript Enhancments כדי להגדיר את ה-Enum בצד-לקוח.
מה מסתבר? Microsoft AJAX לא רק מביא לנו אפשרויות תקשורת מעניינות, אלא גם הוא הרחיב את שפת ג'אווה סקריפט.
באמצעות Microsoft AJAX ניתן להגדיר Enumים בצד-לקוח בג'אווה סקריפט.
אם זו ההגדרה של myEnum ב-#C
אז זו תהיה ההגדרה של myEnum בג'אווה סקריפט
נחזור ונדגיש שחזרנו לעבוד עם החזרה רגילה של Enumים (שלמעשה מחזירים את האינדקס הנבחר ב-Enum).
מפאת ש-myEnum מוגדר עכשיו בלקוח, נוכל לקחת את האינדקס הנבחר שקיבלנו בלקוח ולקבל בחזרה Enum בצד-לקוח.
שנריץ נקבל:
יפה, אז עכשיו יש לנו Enum אמיתי לכל דבר בצד-לקוח ולא סתם איזה אינדקס (שלמעשה אינדקס לכלום) או סתם טקסט (שלמעשה לא מייצג כלום).
מה הבעיה עכשיו? יש לנו שכפול קוד בין הצד-שרת ב-#C לבין הצד-לקוח בג'אווה סקריפט.
הרי ההגדרה של myEnum למעשה חוזרת על עצמה, פעם בשרת ופעם בלקוח. ואם נשנה את הצד-שרת ייתכן וכי ההתנהגות צד-לקוח תישבר.
אם נרצה נוכל לנפתור את הבעיה הזו באמצעות #Script, פריימוורק צד-שלישי שמקמפל #C לג'אווה סקריפט. אפשר להוסיף ל-Build משימה שמקמפלת את ה-Enum צד-שרת שלנו ל-Enum צד-לקוח.
נחזור לבעיה שיש לנו עם הפתרון המקורי של שימוש במחרוזת ו-ToString.
אם נחליט על האופציה הזו, נאלץ לשנות את כל הקוד צד-שרת שלנו שבאמת יחזיר רק מחרוזות.
הייתי מעדיף פתרון יותר כוללני כאן, משהו שיאפשר לי להמשיך להחזיר Enumים כרגיל וייתן לי כמה שיותר מידע על ה-Enum בצד-לקוח.
בואו נביט על משהו מעניין בקובץ ה-web.config שלנו (שיופיע רק ב-CTP Enabled Microsoft AJAX Website).
יש כאן משהו מאוד מעניין, מסתבר שכחלק מה-ASP.Net Futures אפשר להחזיר מצד-שרת לצד-לקוח דברים כמו DataSet ו-DataTable והם אוטומטית יומרו לאיזה חיה מוזרה בשם JSON. אנחנו לא מכירים את JSON וגם לא נדבר על הטכנלוגיה הזו יותר מדי, אבל זה כנראה מאוד איזה פורמט תקשורת צד-לקוח צד-שרת מעניין.
מה השלוש שורות האלו של <converters> ב-web.config אומרות לנו?
שכדי להחזיר מצד-שרת DataSetים ו-DataTables אנחנו רושמים משהו שנקרא Converter והוא דואג להמיר אותם לפורמט שניתן לעבוד איתו בלקוח.
אז בואו גם אנחנו ניצור Converter משלנו. לפני זה נחזור ונזכיר שאנחנו מחזירים כרגיל מהצד-שרת Enum:
ניצור מחלקה משלנו שהתפקיד שלה יהיה לקחת Enum כלשהו (לא בהכרח myEnum) ולהמיר אותו לפורמט שנקבל בצד-לקוח Value ו-Index.
נתחיל מלרשת את המחלקה האבסטרקטית JavaScriptConverter.
המחלקה הזו דורשת מאתנו לממש שלושה דברים:
1. SupportedTypes שמחזיר רשימה של טיפוסים בהם ה-Converter הספציפי הזה מטפל
2. Serialize שמקבל אלמנט ומחזיר רשימת ערכים שיהיו זמינים על האובייקט צד-לקוח
3. Deserialize שמקבל ערכים על אלמנט-צד-לקוח והופך אותו בחזרה להמחלקה
במקרה שלנו אמרנו ש-EnumConverter יתמוך בכל Enum, אז נדאג להצהיר על כך ב-SupportedTypes.
נמשיך בלממש את Serialize.
אמרנו הרי שאנחנו תמיד נטפל ב-Enumים, אז נמיר את האובייקט שקיבלנו ל-Enum ולמקרה שקיבלנו משהו שהוא לא Enum נזרוק חריגה.
עכשיו מגיע החלק הבאמת מעניין.
אמרנו ככה - כל Enum שנקבל, נחזיר את הטקסט שלו במאפיין (גם באנגלית: Property) בשם name ואת האינדקס שלו בתוך value.
עוד שנייה גם נראה איך ניגש למאפיינים האלו בצד-לקוח.
את Deserialize לא נממש כי לפחות בדוגמה כרגע לא נשלח בחזרה לשרת ערכים שה-Converter הזה אמור לטפל בהם.
נרשום את ה-Converter ב-web.config שלנו. (בהנחה והוא יושב ב-App_code)
ולמה עשינו את כל העבודה הזו? כדי שנוכל לגשת למאפיינים name ו-value בצד לקוח בג'אווה סקריפט.
ואם נריץ עכשיו את הדף נקבל:
הקוד שעבדנו עליו זמין להורדה כאן - http://www.JustinAngel.Net/files/Example-AjaxEnum.zip