DCSIMG
עמוד הבית| חבילות השירות שלנו| חומר חופשי| צור קשר
WCF 4 Routing Service Multicast sample - בלוג היועצים של מיקרוסופט ישראל

בלוג היועצים של מיקרוסופט ישראל

WCF 4 Routing Service Multicast sample

danny cohen

לדעתי, Routing Service הוא אחת מהתכונות היותר מעניינות שהתווספו ל – WCF 4.0. למרות שניתן לפתח Routing Service עצמאי (ראה לדוגמא את המאמרים של Michele Leroux Bustamante's  תחת הכותרת "Building a WCF Router") עדיין הגיוני יותר לבחון שימוש ב- Routing Service שמגיע OOTB עם .NET 4.0.

יש לא מעט מקורות מידע בנושא Routing Service, ואני אנסה שלא לחזור על החומר שמתואר בהם. בסוף הפוסט הזה ניתן למצוא לינקים לרשימת מקורות המידע המומלצים בעיניי.

עם זאת, ולמרות קיומם של מספר דוגמאות, לא הצלחתי למצוא דוגמא המתארת את היכולת לבצע Multicasting של הודעות (וזוהי התכונה בעלת פוטנציאל רב לדעתי). הדוגמא הקרובה ביותר שמצאתי בנושא היא AdvancedErrorHandling שעושה שימוש בשני תורי MSMQ על מנת להדגים כיצד ניתן לכתוב הודעה אחת לשני תורים: אחד כיעד ההודעה, והשני למטרת Logging.

אז בפוסט הזה אני אציג sample שמיישם את יכולת ה – Multicasting של WCF 4.0 Routing service. אך לפני שנקפוץ לתוך הקוד, אני מעוניין להסביר איך הסיפור הזה משתלב בתמונה הכללית של תבניות (patterns) הרלוונטיות לנושא.

Routing Service ומפת התבניות הרלוונטית

האפשרות לבצע routing מבוסס על בסיס תכני ההודעה (CBR, או Content Based Routing) היא יכולת שכלולה ברשימת התבניות הבסיסית של מוצרי ESB שונים (הבה נכנה אותם "ESB Usage Patterns").

האיור הבא מתאר את מפת התבניות הרלוונטית ל – ESB, והיחסים ביניהם (ישנה נטייה מסוימת לקרוא בשמות שונים לתבניות דומות, אבל הבה לא ניכנס כרגע לדיוני נומנקלטורה משמימים). מידע נוסף בנושא תבניות בתחום האינטגרציה ניתן למצוא באתר http://www.eaipatterns.com  של Gregor Hohpe's, ובאופן כללי אני ממליץ בחום על ספרו בנושא.

ESB-CBR Patterns - OneWayService sample

ניתן ליישם את כל התבניות הנ"ל באמצעות ובשילוב Routing Service (אחרי הכל, Routing Service הינו רכיב המרחיב את WCF.

למטרות ה – smaple המתואר בפוסט הזה, אני מתמקד (בהתייחס לתרשים הנ"ל) ביכולות הבסיסיות של Routing Service וביישום של יכולות ה – multicast, תוך יישום תבנית שניתן לכנותה בהקשר זה כ – scatter-only (להבדיל מ – scatter-gather המופיע בתרשים).

דרך נוספת להציג את הקונטקסט של ה – sample, היא ע"י סקירה של היכולות הבסיסיות של Routing Service עצמו, כפי שהן מתוארות בתרשים הבא:

Routing Patterns

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

אז, הבה נעשה קצת multicasting:

תיאור ויזואלי של מה שמבצע ה – sample ניתן לראות בתרשים הבא:

Routing Service Multicast

הקליינט שולח הודעה דרך ה – Routing Service תוך שימוש בכל binding זמין (במקרה זה אני עושה שימוש ב – WsHttpBinding, אך כל binding אחר יכול לשמש למטרה זו). ה - Routing Service מעביר (routes) את ההודעה למספר כלשהו של שירותים (destination services) אשר לקיומם הוא מודע באמצעות הגדרות בקונפיגורציה (באמצעות קוד או קבצי קונפיגורציה). העברת ההודעות לשירותים מתבצעת תוך יישום פילטרים או חוקים המגדירים את מדיניות ההעברה (באמצעות מודל של Message Filters – ראו הרחבה בהמשך הפוסט).

ל - Routing Service יש גם את היכולת להגדיר ולעשות שימוש ב – Backup Endpoints המוגדרים ספציפית לכל נקודת שירות (Service Endpoint). במקרה של תקלה במשלוח הידיעה לנקודת שירות זו או אחרת, ה – beckup endpoint  המקושר אליה יקבל את ההודעה במקומה, כיישום failover.

שימו לב שלא כללתי בדוגמא זו יישום של UDP transportation, למרות שהדבר מתבקש בכל דיון שעוסק ב – multicasting. ישנו יישום לדוגמא של UDP כ – WCF Sample, וניתן לעשות בו שימוש כ – binding בהקשר זה, אם כי זה כבר נושא לפוסט אחר.

ועכשיו - הגיע הזמן לראות קצת קוד.

The Client:

נתחיל עם ה – contract שמשתפים ביניהם ה – client ו – services. מדובר על contract שמיושם כ – interface פשוט למדי. שימו לב כי יישום multicast דורש יישום של one-way, היות ומדובר על תבנית של scatter-only ולא של scatter-gather מסוג כלשהו.

Multicast Interface

ה – contract הבא משותף בין ה – client וה – service. שימו לב של – Routing Service אין כל היכרות עם ה – contract הספציפי הזה, היות והוא אמור להיות אגנוסטי ל – contract או ה – interface הספציפי שאיתו עובדים ה – client ו – services מולם הוא מתקשר.

כאמור, ה  -client שולח הודעת one-way רגילה למדי ל – Routing Service, ללא כל מודעות או התאמות לכך שמדובר ב – routing service ולא ב – service עצמו. ההתאמה היחידה הנדרשת היא כמובן שהכתובת (address) שבה ייעשה שימוש ה – client תהיה כתובתו של ה - Routing Service.

ב – interface שלעיל ניתן לראות שנשלח גם מידע על זמן משלוח ההודעה (כ - ticks). מטרת הפרמטר היא לאפשר ניטור של משך זמן משלוח ההודעה מה – client ל – service דרך ה - Routing Service. המידע מוצג הן ע"ג ה – client console והן ע"ג ה – service console (צילומי מסך בהמשך הפוסט). חשוב לציין כי נתוני זמני הביצועים יהיו אמינים ומדויקים רק כאשר גם ב – client וגם ה – service ממוקמים ע"ג אותו שרת\מחשב (ה - Routing Service יכול להיות ממוקם ע"ג שרת מרוחק).

Multicast client code

The destination service:

למטרות ה – sample יושמו מספר endpoints על גבי ה – service, כאשר כל endpoint מיישמת binding מסוג אחר. היישום מבוצע במתודה בשם "GenerateEndpoints".

Multicast endpoints code

מעבר לזאת, ה – service הוא רגיל למדי. החומר המעניין נמצא, כצפוי, ב - Routing Service.

The Routing Service:

בצד של ה - Routing Service, החומר המעניין מרוכז בעיקר במתודה בשם "ConfigureRouterViaCode". מרכז הפעילות במתודה הוא סביב אובייקט בשם RoutingConfiguration אותו יוצרים, מגדירים ומזינים לתוך ה – ServiceHost.

Multicast routing configuration code

סדר הפעילות, בקצרה, הוא:

  1. יצירת אובייקט RoutingConfiguration
  2. יצירת רשימת ה – endpoints של ה – services אליהם יש לשלוח הודעות (הרשימה תאוחזר, מן הסתם מתוך מאגר מידע כלשהו, כגון בסיס נתונים זה או אחר).
  3. הוספת כל endpoint לרשומה משלו באוסף ה  - Filter Table, תוך ציון ה – Message Filter המתאים (הרחבה בהמשך).
  4. אופציונאלית, ניתן להגדיר לכל endpoint גם backup endpoint תואם.
  5. לסיום, הוספת ה - RoutingConfiguration ל – routing behavior, והוספת ה – routing behavior ל – ServiceHost.

חשוב להדגיש כי ה - Routing Service  אינו מודע ל – contract type שאיתו עובדים ה – client ו\או ה – service. ה - Routing Service עושה שימוש ב – contract ייעודי שמטרתו לאפשר העברת ההודעות באופן שמתעלם מה  -contract הספציפי ומודע רק ל – Message Exchange Pattern (ה - MEP) בו נעשה שימוש.

.Multicast routing contract code

ב – sample זה, אנו עושים שימוש ב – ISimplexDatagramRouter, אשר, כפי ששמו מרמז, מהווה interface פשוט לייצור contract שמיועד להעברת הודעות כ – datagram (כלומר: בסמנטיקה של one-way). ניתן לעשות שימוש במספר contracts / interfaces אחרים של Routing Service ליישום sessions (ISimplexSessionRouter), וכן ליישום Request/Reply MEP (IRequestReplyRouter).

כברירת מחדל ב – sample זה, ה - Routing Service מעביר את כל ההודעות לכל ה- services המוגדרים ב – routing configuration. זאת, מכיוון שנעשה שימוש בדוגמא שלעיל ב – MatchAllMessageFilter. יש עוד מגוון של Message Filters אחרים שמגיעים OOTB, אך גם מאוד קל ליישם Custom Message Filters באופן עצמאי. ב – sample כלולים שני Custom Message Filters אשר מאפשרים לבצע routing בהתאם לבדיקת והשוואת ערך ה – SOAP Action header וכן ע"י השוואות ערכים ב – Message Body (היישום אינו אופטימלי בהיבטי ביצועים, אך ניתן לתקן זאת בהשקעה נמוכה יחסית, ובהתאם לתסריט הספציפי הנדרש ליישום).

לדוגמא, דוגמאת הקוד הבאה, מציגה את ה – ActionContainsMessageFilter הכלול ב – sample.

Multicast custom MessageFilter code

ניתן להפעיל message filter מסוים באמצעות שורת הקוד הבאה, הממוקמת (כהערה שניתן לבצע לה uncomment) במתודה ConfigureRouterViaCode שצוינה לעיל:

Multicast custom MessageFilter using in code

הפעלת שורת קוד זו תאפשר העברה רק של הודעות אשר ב – SOAP Action header שלהם מופיעה המילה "Write".

ניתן להגדיר את ה – Routing Service באמצעות קובץ קונפיגורציה סטנדרטי (app.config או web.config), אך ב – sample בחרתי לבצע זאת בקוד מסיבות שכבר צוינו. עם זאת, ב – sample כלול קובץ קונפיגורציה לדוגמא אשר יכול להדגים זאת.

הפעלת ה - Sample:

ה – sample כולל שלושה executables:

  • client console
  • Routing Service console
  • service console

מסיבה זו, ה – solution הוגדר להפעלה של Multiple Startup Projects:

Multicast solution startup settings

חשוב לשים לב שה – client מוגדר ש – Start without debugging. הסיבה לכך היא באג אשר מתיו סניידר, ה – Program Manager של Routing Service, הסב את תשומת ליבי לקיומו. כאשר פרויקט WCF נמצא ב – debug mode, ה – debugger מוסיף custom SOAP header ייחודי להודעה. במקרה של Routing Service, היות וגם ה – client וגם ה - Routing Service עצמו יכולים להיות תחת debugger, יתבצע ניסיון גם ב - Routing Service עצמו להוסיף את אותו ה – custom SOAP header, אך מכיוון שהוא כבר שם, תתרחש שגיאה. המעקף לכך הוא פשוט מאוד – הפעלה של ה – client או ה - Routing Service שלא תחת ה – debugger, כפי שמתבצע ב – sample זה.

לחיצה על F5 מפעילה את 3 ה – executables ומאתחלת את הרכיבים, כאשר ה – client ממתין לאישור פעולה של המשתמשע"י לחיצה על enter.

לחיצה על enter בחלון ה – client תשלח הודעות אתחול ל - Routing Service ותספק היזון חוזר לגבי הביצועים ההתחלתיים.

Multicast client init message

שימוש לב שבאתחול, ההודעה הראשונית יוצאת לאחר פרק זמן ארוך יחסית, בשל אילוצי אתחול רכיבים ו – transport.

בצד השירות, ניתן לראות כי הודעה אחת אשר נשלחה ע"י ה – client, הופצה ע"י ה - Routing Service למספר רב של endpoints מסוגים שונים, בהתאם להגדרות ב - RoutingConfiguration settings.

Multicast routing init message

עם משלוח ההודעה השנייה ע"י ה – client, ניתן לראות את הביצועים הסטנדרטיים של הרכיבים לאחר האתחול:

Multicast client 2nd message

והנה התוצאה במסך ה – service:

Multicast routing 2nd message

קוד מקור של ה - sample:

ניתן להוריד את הקוד של ה – sample בלינק הזה. חשוב לציין שדוגמת הקוד ניתנת כמות שהיא, ללא אחריות או התחייבות כלשהי, מפורשת או משתמעת.

מקורות מידע נוספים על Routing Service:


danny cohen שמי דני כהן ואני ארכיטקט ויועץ בצוות MCS Israel, ומתמחה במערכות מבוזרות, Cloud Computing, מתודולוגיות פיתוח וארכיטקטורת תוכנה.

תוכן התגובה

Vardi כתב/ה:

הי דני,

אחלה פוסט. אני אישית מעדיף לעשות את כל ההגדרות של ה -

Routing Service בקובץ Config, יותר קל לתחזוקה.

# March 3, 2010 4:30 PM

Tal Ben-Shalom כתב/ה:

משובח.

דני, 2 שאלות:

1. עבור אלו תרחישים/סוגי אפליקציות אתב רואה צורך או שימוש ב- routing service?

אני רואה את זה כרכיב מוביל למימוש pub-sub וכמובן במידה ויש צורך ב - backup service. אלו עוד?

2. אפרופו לנקודה שורדי העלה - אם זכרוני אינו מטעני בגרסאות קודמות לא נתן היה להגדיר את ה- routing table ב - runtime, או יותר נכון, לאחר שה - service אותחל. האם יש שינוי בנושא?

# March 3, 2010 9:46 PM

אליק כתב/ה:

משובח בהחלט!!

נשמר אצלי בספרית ה-KB של WCF

# March 3, 2010 11:28 PM

Yossi Elkayam כתב/ה:

דני , משובח ומפורט! יופי של פוסט. תודה רבה.

# March 3, 2010 11:31 PM

Danny Cohen כתב/ה:

@Vardi -

היי אייל, ותודה רבה.

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

ראה:

blogs.msdn.com/.../routing-service-features-dynamic-reconfiguration.aspx

דני.

# March 5, 2010 11:56 PM

Danny Cohen כתב/ה:

@TAL -

היי טל, ותודה רבה.

1. כל תרחיש שיש בו צורך ליישם אחד או יותר מה - Patterns שתיארתי (וכנראה גם כמה אחרים). אני חושב שהרבה יותר נוח לדבר במונחי patterns ולא במונחי תרחישים, היות ואז קל יותר לזהות את הקשר בין הצורך לפתרון.

2. ראה את התשובה שרשמתי לוורדי, וספציפית את הלינק המצורף שמסביר זאת מצוין.

לא ברור לי לאילו גרסאות קודמות אמת מתכוון. routing service הוא יישום חדש ל - .NET 4.0.

דני

# March 5, 2010 11:59 PM

שלומי הסן כתב/ה:

דני מאמר מעולה

כיף לקרוא מאמר מקיף בנושאים כאלו ולא פוסטים קצרים

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

# March 29, 2010 11:25 PM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 2 and 6 and type the answer here:


Enter the numbers above: