מסתבר, שאחת הדרכים המוכרות והפשוטות ביותר לשליחת וקבלת מידע ע"י פלאש היא באמצעות המחלקה LoadVars של ActionScript. למעשה, המימוש של LoadVars דומה יותר לטעינת קובץ מקומי מאשר למימוש תקשורת על גבי פרוטוקול HTTP, כשהקשר היחיד ביניהם הוא אירוע onHTTPStatus, שמחזיר את קוד המצב של הHTTP כשזה משתנה.
המחלקה LoadVars מסוגלת לבצע שאילתות GET וPOST, ולקבל נתונים בפורמט application/x-www-form-urlencoded שזה בעצם אותו פורמט הנתונים שמשמש אותנו למסירת פרמטרים בURL, וכן להעברת תגיות הFORM על גבי פרוטוקול HTTP בשאילתות POST. המעלה הברורה כאן היא הפשטות, כשהחיסרון, הבולט לא פחות, הוא הצורך לקודד הכל ובכך להכפיל את כמות התעבורה ברשת. חיסרון נוסף הוא היעדר אפשרות מובנית לביטוי הירארכיה (כמו JSON או XML), אך זה ניתן לתיקון ע"י יצירת פורמט נתונים מותאם אישית. אך לא על זה באתי לדבר.
במאמר הזה באתי לתאר פתרון שכתבתי לצורך תקשורת יעילה בין אפליקציית Web בASP.NET לבין אפליקציית Flash באמצעות המחלקה LoadVars.
חיפוש קצר באינטרנט יגלה המון דרכים שונות לביצוע המשימה. רובם ישתמשו בדף aspx ללא תוכן HTML, או בWebServices מורכבים, כשלשתי הגישות אותו החיסרון - הטכנולוגיות הללו פשוט לא מיועדות לזה. השימוש בPage גורר ביצוע של כמויות אדירות של קוד האחראי לתמיכה בControls ללא שום צורך בכך (שהרי הדף לא מיועד לפלוט HTML), וWebServices דורשים כתיבת adapterים מיוחדים ליצירת הפורמט הרצוי. בנוסף, שני הגישות הקודמות פשוט לא מאפשרות אינטגרציה חלקה (ברמה של Silverlight-ASP.NET לדוגמה). הפתרון שאני כתבתי מורכב מHttpHandler בשם LoadVarsHandler, שמיועד במיוחד עבור המטלה הזו – לעבוד מול LoadVars של הפלאש, ושני מחלקות יורשות:
- LoadHandler – לעבודה מול LoadVars.load
- SendAndLoadHandler – לעבודה מול LoadVars.sendAndLoad
המאפיין החשוב ביותר עבורי היה לאפשר כתיבה הצהרתית (declarative programming), שתאפשר באופן מילולי לקרוא לשיטה של NET. מתוך הפלאש.
אביא לדוגמה יישום פשוט שמקבל שם מפלאש ומחזיר ומחזיר שורה "שלום [שם]!":
ActionScript:
btn.onRelease = function() {
postToServer("SayHello", {name: txt.text});
}
function postToServer(action:String, parameters:Object) {
var lv:LoadVars = new LoadVars();
lv.onLoad = function(success){
if(success) {
if (lv.$error) {
txtAnswer.text = lv.$error;
} else {
txtAnswer.text = lv.message;
}
} else {
txtAnswer.text = "undetermined error";
}
}
lv.action = action;
for(var par in parameters) {
lv[par] = parameters[par];
}
lv.sendAndLoad("sayhi.flash", lv, "POST");
}
C#:
namespace Flash
{
[AccessRule(AccessRuleType.AllowUser, "*")]
public class SayHiController : SendAndLoadHandler
{
[FlashAction]
public void SayHello(string name)
{
if (!string.IsNullOrEmpty(name.Trim()))
{
FlashResponse.AddParameter("message", "Hello " + name);
}
else
{
FlashResponse.AddParameter("message", "Please enter your name.");
}
}
}
}
הסבר
בדוגמה שלפנינו ניתן לראות בקטעים המודגשים בקוד ActionScript, שאנחנו קובעים למשתנה בשם action, שעל האובייקט LoadVars, את הערך "SayHello" – ובכך בעצם אומרים שאנחנו מעוניינים להריץ את המתודה בשם SayHello! שאר המשתנים שעל LoadVars מועברים כארגומנטים למתודה הזאת. במקרה שלנו ישנו ארגומנט בשם name מסוג String שאליו אנו מעבירים את השם שנקלט. עצם הקריאה לפונקציה והעברת הפרמטרים מבוצע באמצעות reflection באופן שקוף ע"י המחלקה SendAndLoadHandler! כל מה שעלינו לעשות הוא לסמן את המתודה הרצויה ע"י האטריבוט FlashActionAttribute, ולקבוע את ההרשאה עבור המחלקה כולה לכל המשתמשים.
בקוד צד השרת כבר אין צורך בפענוח הForm, המרת הפרמטרים, ומציאת המתודה המתאימה (במקרה שיש יותר מאחת) – כל זה נעשה עבורך מאחורי הקלעים! כל מה שנשאר לעשות הוא להוסיף פרמטרים לתגובה ע"י קריאה לFlashResponse.AddParameter עם שם וערך הפרמטר!
מיפוי המחלקה SayHiController לכתובת sayhi.flash מתבצע ע"י הוספת שורה בweb.config בפסקה <httpHandlers>, לדוגמה:
<httpHandlers>
...
<add verb="*" path="sayhi.flash" type="Flash.SayHiController" />
...
</httpHandlers>
בגרסתה הנוכחית (הראשונה) תומכת המחלקה ב:
- הרשאות מבוססות על אבטחת שמשתמש\תפקיד של ASP.NET
- מיפוי שם נרדף למתודה ע"י מתן פרמטר לFlashActionAttribute
- המרה אוטומטית של טיפוסים בפרמטרים (באמצעות TypeConverter)
- העברת פרטי חריגים לא מטופלים לFlash באמצעות המשתנה error$ (ראה דוגמה)
לסיום אביא דוגמה קצרצרה של שימוש במחלקה LoadHandler (שעובדת מול LoadVers.load של ActionScript כאמור):
namespace Flash
{
[AccessRule(AccessRuleType.AllowUser, "*")]
public class SomeSettings : LoadHandler
{
[FlashVariable]
public string FirstName
{
get
{
return "Daniel";
}
}
[FlashVariable]
public string LastName
{
get
{
return "Katz";
}
}
}
}
בדוגמה הזאת התכונות FirstName וLastName יועברו אוטומטית לפלאש כמשתנים על האובייקט LoadVars! את הקוד המקביל בActionScript קל מאוד לדמיין ולכן לא אביא אותו כאן.
סוף דבר
אחזור ואציין שהעברת מידע דרך LoadVars משרתת את הצרכים הבסיסיים בלבד, ואם יש צורך בהעברת מידע בעל הירארכיה כדאי לקרוא על מימושים של JSON עבור NET. ולActionScript (ניתן למצוא כאן - English).
קוד המקור והקבצים הבינאריים זמינים להורדה מכאן.
אני מאוד מקווה שתמצאו את הספרייה שכתבתי מועילה, ותכתבו לי פה, או בדף הפרויקט בגוגל, על הניסיון שלכם עם הספרייה – לטוב ולמוטב.