יום ראשון, 27 בינואר 2013

XML to XSD to C# class

לאחרונה כתבתי שרות WCF. כחלק מהדרישות קיבלתי סכמה (או יותר נכון קיבלתי XML שממנו הייתי צריך ליצור סכמה..)- שהיא צריכה להיות התשובה שאני מחזיר באחד הפונקציות שאני חושף בשרות.

ממבט ראשון אפשר לחשוב שיש לנו קצת עבודה בעניין (להפוך את ה XML לסכמה, ולכתוב Class שנוכל לעבוד איתו, וכמובן שיהיה סריאליזבילי), אבל למזלי גיליתי (בעזרתו של חבר) שיש כלי נהדר שמגיע עם NET4.  בשם xsd.exe , שיוצר לנו באופן אוטומטי קובץ XSD על פי XML , והיותר חשוב-יצירת  c# classes מתוך ה XSD.

את הדוגמא של קובץ ה XML  לקחתי מהאתר w3schools.

הפיכת Xml ל Xsd:

ה XML:

הפעילו את " Visual Studio Command Prompt"

הקישו את הפקודה הבאה:


כעת נוצר לנו קובץ ה Xsd:
הפיכת Xsd ל C# class:
כעת הדבר החשוב: (מוכנים?)

הקישו את הפקודה הבאה:

ואיזה פלא: נוצר ה Class הבא: (חלק ממנו)

תהנו!

יום שבת, 19 בינואר 2013

Integration patterns part1- Claim Check

Claim Check זוהי תבנית עיצוב שימושית מאוד בעולם האינטגרציה.
תארו לכם את המצב הבא: יש לכם טיסה מישראל לארה"ב. הטיסה לא ישירה ויש לכם כמה קונקשנים. יש לכם 2 מזוודות גדולות מאוד (מתנות לדודים). במקום לקחת איתכם את המזוודות הכבדות למטוס, להיסחב איתם, לעבור את כל הקונקשנים שלכם איתם (דבר שכמובן גם יאט אותכם בדיוטי פרי), מה שתעשו זה תמסרו את המזוודות בדלפק (Check), תקבלו כרטיס עם המזהה של המזוודות שלכם, וכשתגיעו לארה"ב (אחרי כל הקונקשנים, דיוטי פרי, וכו') אתם תקחו את המזוודות (Claim).

ועכשיו לעולם התוכנה- (אעשה שימוש לדוגמא במושגים מ Biztalk):
אנחנו נתקלים המון במצב הבא: מקבלים הודעה עם Data גדול. לרוב אנחנו לא צריכים לעשות שימוש ב Data (אנחנו רק רוצים להעביר אותו הלאה), אבל אנחנו צריכים את כל נתוני המסגרת (Meta-data). 
אנחנו רוצים להמנע מלהכניס הודעות גדולות ל MsgBox -זה יכול להאיט את המערכת שלנו, ואף לגרום לthrottling  במערכת, וגם למשל לבצע מיפויים, או תהליכים לוגיים כלשהם על קובץ גדול- יכול לגרום לבעיות ביצועים חמורות.

אז בגדול זה עובד כך:

נסביר:
  1. נקבל ב Receive הודעה. (עם Data). נפריד את ה Data מההודעה, נצמיד לו מזהה, ונעשה Check להודעה (יכול להיות לדיסק, לתור, במקרים אחדים אפשר גם ל Cache.
  2. נבצע את התהליך שאנחנו רוצים לבצע על ההודעה, ללא ה Data
  3. כאשר ההודעה תגיע ל Send, נבצע עליה "העשרה", כאשר נצמיד להודעה את ה Data ששיך לה ( Claim)
פשוט מאוד.

תהנו!

יום שבת, 12 בינואר 2013

Change controls from non-main thread in WPF or Winform

קצת היה לי קשה לכתוב את הכותרת בעברית. כאשר אנחנו כותבים אפליקצייה כלשהי, או קליינט ב WPF (רצוי) או WINFORMS אז לרוב אנחנו צריכים לעדכן פקדים ב GUI שלנו (כמו Progress Bar או תוויות טקסט שונות, או כל דבר אחר). אני לפעמים רואה מתכנתים שקצת "מסתבכים" עם זה ועושים זאת בדרכים "עקיפות" וקצת מסובכות.

אני אציג את הפתרון שלדעתי הוא הפתרון הנכון.

בניתי טופס לדוגמא ב WPF (קצת מכוער אבל רק בשביל הדוגמא) שמכיל כפתור, תווית טקסט ו Progress Bar:

ה"אפליקצייה" המדהימה עושה את הבא: בעת לחיצה על הכפתור, יופעל Thread שמפעיל פונקציה כלשהי (במקרה שלנו היא "מורידה קבצים" מהשרת. כל מה שהפונקציה רוצה זה לעדכן את ה ProgressBar, ולעדכן ב GUI את שם הקובץ שיורד כרגע.

private void buttonStart_Click(object sender, EventArgs e)
  {
      Thread SomeThread = new Thread(foo);
      SomeThread.Start();
  }       

ניצור ב class של הטופס EventHandler שמקבל GuiEventArgs:

public event EventHandler msgRecieved;      

וכמובן ניצור GuiEventArgs ונכניס בו את כל הפרמטרים שאנחנו רוצים להעביר בהודעה ל GUI:
public class GuiEventArgs : EventArgs
 {
     public int Progress { get; set; }
     public string DownloadedFile { get; set; }

     public GuiEventArgs(int progress, string downloadedFile)
     {
         Progress = progress;
         DownloadedFile = downloadedFile;
     }
 }     

בפונקציה שלנו אנחנו נרשמים ל Event עם הפונקציה שאנחנו רוצים שתורץ כאשר ה Event מופעל, ולאחר מכן אנחנו מפעילים את ה Event עם הערכים שאנחנו רוצים לשלוח לטופס:
void foo()
 {
     //initialize the value for progressbar
     int progressValue = 10;

     while (true)
     {
         //sign to the event
          msgRecieved += new EventHandler(MainWindow_msgRecieved);

          //invoke the event
          msgRecieved.Invoke(new object(), new GuiEventArgs(progressValue,"Any name"));
          progressValue += 10;
          Thread.Sleep(100);
     }
}
ה Event מריץ את הפונקציה הבאה:
void MainWindow_msgRecieved(object sender, GuiEventArgs e)
 {
     Dispatcher.Invoke((Action)(() =>
     {
        progressBar1.Value = e.Progress;
        labelDownloadingFile.Content = e.DownloadedFile;
     }));           
 } 



אם היינו כותבים ב WINFORMS אז ההבדל היחידי היה שבפונקציה הנ"ל היה Invoke((Action) ללא ה Dispatcher.
הסבר קצר:

ה Dispatcher הוא סוג של "תור" שמקבל בקשות, ואחראי לשלוח את הבקשות על פי עדיפות. במקרה שלנו הוא שולח את הבקשה ל Thread הראשי של ה GUI, וזה מאפשר לנו בקלות לעדכן ערכים בפקדים שנמצאים ב GUI מ Thread נפרד

יום רביעי, 9 בינואר 2013

Biztalk Orchestration best practices

אני מפתח על גבי Microsoft Biztalk 2010. בצוות הפיתוח שלי לפעמים לא מקפידים לשמור על כללים לפיתוח נכון באורכסטרציה, או אם תרצו "איך לא מפתחים באורכסטרציה":

  1. להימנע מ overuse (שימוש יתר)- אורכסטרציה היא כלי נהדר, אבל השימוש בה כולל עלות מסויימת- עלות של הפנייה ל MsgBox. עלות זו יקרה משום שמתבצעת פנייה לדיסק.. מפתחים נוטים להשתמש באורכסטרציה כי זהו כלי גראפי. העצה היא להימנע מפעולות פשוטות באורכסטרציה.
  2. להימנע מאורכסטרציות גדולות- בדיוק כמו בגישת OOP, כשאנחנו כותבים קוד, אנחנו לא כותבים פונקציות ארוכות. בפיתוח באורכסטרציה נהיה קל למפתח לגרור shapes ועל ידי כך להגדיל את האורכסטרציה ולגרום לה להיות קשה למעקב. Call orchestration shape זה דרך טובה לפצל את האורכסטרציה. זה עובד כמו בקוד כאשר קוראים לפונקציה- אפשר לשלוח ולקבל פרמטרים (פועל באופן סינכרוני). אם אנחנו רוצים להפעיל את האורכסטרציה באופן א-סינכרוני נשתמש ב Start orchestration (אבל זה יוצר context חדש ב MsgBox)
  3. להקטין ככל האפשר את מספר הפניות ל MsgBox - בכל נק' שבה האורכסטרציה יוצרת קשר עם העולם החיצון המצב נשמר ב MsgBox. מצב זה נקרא persistence points.  במצב זה נשמרים כל ההודעות והמשתנים של האורכסטרציה. Send shapes הם ה persistence points הנפוצים ביותר. דרך טובה להימנע ממצבים אלו (במידה ויש מספר shapes) היא להכניס כמה Send shapes לתוך atomic operation אחד. זה יגרום ל persistencePoint אחד ויחיד.כמובן שסדר ההודעות שהאורכבטרציה תקבל יהיה הסדר שבו ה recieve shapes מסודרים. דרך טובה לבדוק כמה persistence points האורכסטרציה מבצעת היא ע"י שימוש ב perfmon תחת ה counter תחת אובייקט ה XLANG/s Orchestrations
  4. לעולם לא להשתמש ב XmlDocument-
    •  אפשר לבצע השמה של הודעות שהם non-xml לתוך XmlDocument. בזמן קומפילציה לא נקבל שגיאה, אך בזמן ריצה ייזרק Exception. זה יכול להיגרם כאשר מתכנת אחר מגיע לבצע שינויים באורכסטרציה שלנו והוא לא שם לב מה סוג ההודעה.
    • גרוע באופן צריכת הזכרון- XmlDocument מעלה את האובייקט ל DOM בשביל עיבוד, ויותר גרוע מזה, כדי לאפשרב DOM גישה מהירה אז האובייקט שעלה לזכרון יהיה יותר גדול מהאובייקט XML (לדוגמא 100K של הודעה יכולה להפוך ל 1MB)
    • שינויים בתוכן- XmlDocument מאפשר לשנות את ההודעה, אך השינוי לא מבוצע ב MsgBox, ותחת תנאי קיצון כמו persistence points השינויים שלי לא ישמרו. הדרך הנכונה היא להשתמש ב XMLLANGMessage, XmlReader, XDocument.
  5. להשתמש ב distinguished במקום ב xpath- ב אפשר להשתמש באורכסטרציה ב xpath על ההודעה :                      xpath(message/part, xpathExpressionString) . זה יכול להיות שימושי מאוד, אבל הבעיה מתחילה כשצריך להכניס את ה namespace לתוך ה expression וזה מתחיל להיראות לא ידידותי:                                 
xpath(MyMessage, "/*[local-name()='MyMessage' and namespaceuri()= http://nova/billing/schemas/internal/2011-05'] /* [localname()='Number' and namespace-uri()='']") = "1234";

        אם היינו משתמשים ב distinguished זה היה נראה  MyMessage.Number="1234
         
        עוד בעיה זה כאשר ה namespace משתנה (למשל אם מעדכנים לגירסא NET4. ) אז צריך לשנות בקוד את כל  המקומות שכתבנו בהם את ה namespace. ב distinguished זה לא היה קורה

שבוע טוב,