סדרת לומדים Validation Application Block עם חשפניות
1. קדם דבר: למה צריך וולידציה? (או: "קופים. פשוט קופים."), פורסם ב-26.6.2007
2. חלק ראשון: הפתרון הקיים והמצוי ב-Winforms, Console ו-ASP.Net (או: "איך קוראים לך ובת כמה את?"), פורסם ב-8.7.2007
3. חלק שני: שימוש ישיר ב-Validatorים של VAB (או: "איך לגרום לקוד יחסית קריא להפוך להיות ארוך ומעיק"), פורסם ב-9.7.2007
4. חלק שלישי: הכנסת נתוני הוולידטורים לתוך מחלקות (או: "ממלכתי עבור וולידטור ג'נארי"), פורסם ב-10.7.2007
5. חלק רביעי: אינטגרציה בסיסית עם ה-GUI ו-וולידציה מתוך קבצי קונפיוגרציה (או: "קצת יותר Drag&Drop, קצת פחות קוד"), פורסם ב-11.7.2007
6. חלק רביעי המשך: אינטגרציה בסיסית עם ה-GUI ו-וולידציה מתוך קבצי קונפיוגרציה (או: "קצת יותר Drag&Drop, קצת פחות קוד"), פורסם ב-12.7.2007
7. המשך יבוא.
חלק רביעי: אינטגרציה בסיסית עם ה-GUI ו-וולידציה מתוך קבצי קונפיוגרציה (או: "קצת יותר Drag&Drop, קצת פחות קוד")
נושא נוסף שנרצה לראות הוא כללי וולידציה בתוך קבצי קונפיגיורציה.
כן, בנקודה הזו אני פשוט משלב תמונות של חשפניות (ספציפית של הזמרת קיילי מינוג) בלי קשר לנושא. נראה כמו מדיניות טובה וסולידית להמשך מאמר זה.
איפה היינו? אהה, כן, קבצי קונפיוגרציה.
זוכרים את קבצי ה-App.config וה-web.config? מסתבר שאפשר להוסיף לתוך קבצי קונפיוגרציה כאלו את רשימת הכללי וולידציה של הישות העסקית שלנו. כלומר, במקום הישות כפי שהיא נראית עכשיו:
נוכל לכתוב את כללי הוולידציה בתוך קובץ ה-config שלנו עם איזה תחביר XMLי מוזר.
ניצור בפרוייקט ה-BL שלנו קובץ config בשם BL.config.
ונקבל בקובץ ה-BL.config:
נרצה להוסיף תגית <validation> בתוך התגית <configuration> שבתוכה נוכל לכתוב את כללי הוולידציה שלנו.
בשביל זה נוסיף בתוך תגית ה-<configsections> (שהיא תמיד התגית הראשונה בתוך תגית ה-<configuration>) הצהרה על כזו תגית <validation>.
הוספנו תגית <validation> שנקבע לפי ה-name וההגדרה שלה מפורטת בתוך המחלקה Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidationSettings.
נרצה עכשיו להוסיף וולידציה ל-BL.Stripper.
נוסיף תגית <type> חדשה לתוך <validation> ובה נקבע Assembly ו-Type שמתאים לטיפוס BL.Stripper.
עכשיו נוסיף משהו שנקרא ruleset. אנחנו לא מכירים את החיה המוזרה הזו ונכיר רק בהמשך המאוד רחוק של המאמר. אז כרגע תאמינו לי שזה טוב ליהודים.
ונחליט עכשיו לתרגם את כלל הוולידציה ש-Stripper.Name הוא עם StringLengthValidator בין תו אחד ל-100 תווים. ה-Attribute הבאה תהפוך מהקוד הבא:
לקונפיוגרציה הזאת:
קודם הגדרנו שאנחנו מבצעים וולידציה על מאפיינים של המחלקה באמצעות תגית ה-<properties>. (ניתן גם לבצע וולידציה על מתודות ושדות פרטיים)
הגדרנו על איזה מאפיין נרצה לבצע וולידציה באמצעות קביעת name ל-<property>.
ובתוך <property> הגדרנו איזה וולידטורים אנחנו נרצה להריץ.
כדי להשלים את התהליך נצטרך להוסיף עוד כמה מאפיינים ל-<validator>:
name מיועד לזיהוי חח"ע של כלל הוולידציה. ובנוסף פירטנו שה-stringLengthValidator כולל את "1" ו-"100".
נהפוך את ה-RangeValidator מ-Attribute לקונפיגיורציה.
יהפוך ל:
בנקודה הזו כל מה שעשינו זה ליצור קובץ XML מאוד מתוחכם.
הקובץ XML הזה במקרה (או שלא) תואם לקובץ קונפיוגרציה ש-EntLib3.1 יכול לטעון ולהשתמש ב-VAB.
צריך גם להגיד לאפליקציות שלנו שצריך לטעון איכשהו את הקובץ קונפיורציה BL.config.
נוסיף לפרוייקט ה-Winforms שלנו קובץ App.config.
וככה נראה קובץ ה-App.config שלנו:
נרצה עכשיו איכשהו לציין באמצעות קובץ הקונפיוגרציה של האפליקציה שלנו שיילך ויטען את BL.config לקונפיוגרציה של EntLib.
נוכל ציין FileConfigurationSource שיושב בתוך ConfigurationSourceSection של EntLib. נוסיף את ה-ConfigSection הרלוונטי לקובץ ה-App.config:
ונוסיף source שהולך לקובץ BL.config:
(שמנו שלושה סלאשים אחרונית היות ומבנה התיקיות שלנו הוא קודם ללכת אחרונית את ה-debug, אז את bin, אז את תיקיית הפרוייקט ומשם ניכנס לפרוייקט BL ורק שם נמצא את BL.config).
עכשיו שנריץ את האפליקציה נראה ש:
צריך לזכר שהכלל הזה מגיע מתוך קובץ קונפיוגרציה ולא מתוך ה-Attributes של BL.Stripper.
כנ"ל נוכל להוסיף לקובץ ה-web.config של ה-ASP.Net שלנו. נוסיף את ההפנייה לקובץ BL.config ל-web.config:
(יש סלאש אחרונית אחת יחיד היות ואנחנו הולכים מתיקיית הפרוייקט של ה-Web Project ולא מתוך ה-project\bin\deug).
וכאשר נריץ את הפרוייקט, נכניס את הקלט הבא ונלחץ על כפתור ה-submit נראה:
ושוב, ההגדרות וולידציה האלו מגיעות מקבצי וולידציה.
אין שום Attributes על Stripper.
עכשיו, אני לא יודע מה איתכם, אבל אני לא אוהב לכתוב XML ידנית. אבל אני כן מעדיף לעבוד עם GUI או לתכנת בסיטואציות האלו:
בואו נמחוק את קובץ ה-BL.config שעבדנו בעמל רב לכתוב אותו, ונוציא את ההפניות לקובץ ה-BL.config מקובץ ה-app.config של ה-Wifnroms ומקובץ ה-web.config של ה-ASP.Net.
ניצור מחדש את קובץ ה-BL.config כך שכל מה שהוא מכיל אלו תגיות <configuration>.
נלחץ על הקובץ כפתור ימני ונבחר Edit Enterprise Library Configuration.
ונראה את אפליקציית עריכת ה-Configuration של EntLib שתמיד הייתה תוכנה חיצונית ל-Visual Studio עכשיו בתוך Visual Studio.
כפתור ימני על BL.config ונבחר להוסיף ConfigSection שמתאים ל-VAB.
וקיבלנו:
כפתור ימני על Validation Application Block ונבחר להוסיף וולידציה ל-Type נוסף. ספציפית, ל-BL.Stripper.
נקבל את ה-Type Selector של כלי הקונפיוגרציה של EntLib.
נפתח את האסמבלי BL, נפתח את ה-Namespace בשם BL ונבחר את Stripper.
עכשיו נוסיף את ה-default ruleset. שאנחנו עדיין בכלל לא יודעים מה זה, אבל תסמכו עליי פה.
נשנה את השם של ה-ruleset ל-"default".
ונקבע את "default" כ-ruleset ברירת מחדל של Stripper.
(שנגיע לחלק על Rulesetים אני מבטיח שתבינו מה זה Ruleset, עד אז זה לא תורם לנו הרבה כרגע)
כפתור ימני על default ונדאג להוסיף את המאפיינים Stripper.Name ו-Stripper.Age.

ונקבל:
נזכור שאנחנו מנסים לקבוע וולידציה על Stripper.Age מסוג StringLengthContainer בין 1 ל-100.
כך זה נראה ב-Attributes:
[StringLengthValidator(1, 100,
MessageTemplate = "Stripper name is between 1 to 100 charcters")]
public string Name
{
get { return _name; }
set { _name = value; }
}
ובעורך GUI נוסיף StringLengthValidator:
נוסיף גם Range Validator ל-Stripper.Age. כך שיתאים ל-Attribute הזו:
[RangeValidator(18, RangeBoundaryType.Inclusive, int.MaxValue, RangeBoundaryType.Inclusive,
MessageTemplate = "Stripper has to be at least 18")]
public int Age
{
get { return _age; }
set { _age = value; }
}
ונקבל ב-GUI:
נקבע מאפיינים בהתאם לכללי האימות:
נשמור את השינויים בקובץ BL.config ונראה את ה-XML שנוצר:
מאוד דומה ל-XML שעמלנו קשות כדי לכתוב!
עכשיו נרצה להוסיף הפנייה לקובץ BL.config שלנו מקובץ ה-App.config של אפליקציית ה-Winforms וקובץ ה-Web.config של אפליקציית ה-ASP.Net.
כפתור ימני על קובץ ה-Web.config ונבחר Edit Enterprise Library Configuration.
נבחר להוסיף Configuration Sources:
נמחק את ה-System Configuration Source ונבחר להוסיף File Configuration Source.
נקבע במאפיינים שלו שהוא יילך לקובץ ה-BL.config.
וכאשר נפתח ונסגור את ה-Enterprise Library Configuration על קובץ ה-Web.config נוכל לראות שהמאפיינים של VAB זמינים לעריכה בעורך הגרפי. זאת למרות שהם לא פיזית נמצאים בתוך קובץ ה-web.config.
ניתן לחזור על התהליך עבור אפליקציות Winforms, אך עקב בעיות של כלי הקונפיוגרציה אני ממליץ בחום שתישארו בעריכה ידנית של קובץ ה-XML. הבעיה היא שכלי הקונפיוגרציה דורש יצירת קובץ Runtime.App.Config ויצירת קובץ Designtime.App.Config שהראשון מפנה עם שלושה סלאשים אחרונית לקובץ BL.config והשני מפנה עם סלאש יחיד. שני הקבצים כמובן לא מסונכרנים אחד עם השני ולכן עדיף להימנע ממדיניות זו.
בואו נראה אם באמת כל העריכה הגרפית הזו הניבה תוצאה טובה.
ואכן כללי הוולידציה שהזנו דרך הממשק ה-GUI זמינים ב-ASP.Net וב-Winforms.
מתי נשתמש בקבצי קונפיוגרציה מול Attributes?
המצב ההכרחי הוא כאשר יש לנו שתי אפליקציות עם אותן ישויות עסקיות אבל חוקים עסקיים שונים באופן מהותי. לא נרצה להביע בקוד שלנו חוקים עסקיים שונים ואף סותרים היות וזה יקשה עלינו לקרוא ולערוך אותם.
בנוסף אם נצטרך לשנות את החוקים העסקיים שלנו בלי לקמפל את האפליקציה נוכל לערוך את קובץ הקונפיוגרציה אך לא נוכל לשנות Attributes.
כלל האצבע בבחירה בין קבצי קונפיגיורציה לבין Attributes היא השאלה הבאה: "האם הישויות העסקיות שלנו צריכות לדעת מהן כללי הוולידציה שלהן?".
נוכל למשל לשאול "האם BL.Stripper צריך לדעת ש-Name הוא בין תו אחד ל-100 תווים, והאם הוא צריך לדעת ש-Age הוא לכל הפחות 18?".
אם ענינו "כן" לשאלה למעלה, אז הרי שנרצה למען קריאות הקוד ולמען חלוקת אחריות להכניס את הוולידטורים באמצעות Attributes לישויות העסקיות שלנו.
אם ענינו "לא" לשאלה, אז סימן שנרצה לעבוד עם קבצי קונפיוגרציה כדי שהישויות העסקיות יופרדו מכללי הוולידציה החלים עליהן.
מה עשינו בחלק הזה:
- ישמנו אינטגרציה בסיסית של VAB עם Winforms בזה שהוספנו ValidationProvider על הישות העסקית שייכנו אותו ל-ErrorProvider, וקבענו לכל פקד גרפי מאפיין על הישות העסקית שעליו תתבצע הוולידציה.
- הוספנו אינטגרציה בסיסית של VAB עם ASP.Net עם זה שלכל שדה ב-GUI הוספנו PropertyProxyValidator ואמרנו לאיזה ישות עסקית ומאפיין שלה היא קשורה.
- ראינו שאפשר לכתוב כללי וולידציה בתוך קבצי קונפיגיורציה ואיך ניתן להפנות לאותם קבצי קונפיגיורציה מהאפליקציות שלנו.
- ראינו את התהליך הידני שנצטרך לעשות כדי לכתוב כללי וולידציה בקבצי קונפיגיורציה (הוספת configSection, הוספת Type, הוספת ruleset, הוספת Properties, הוספת Property והוספת Validator).
- ראינו כיצד Enterprise Library Configuration tool מקל עלינו ביצירת אותם קבצי קונפיגיורציה.