DCSIMG
November 2011 - Posts - שלמה גולדברג (הרב דוטנט)

שלמה גולדברג (הרב דוטנט)

מרצה בסלע ויועץ בעולם ה - net.

November 2011 - Posts

Exception Message Box

 

מי לא כתב את הקוד הבא:
 

try

{

 

}

catch (Exception ex)

{

    MessageBox.Show(ex.Message);

}

ובכלל הצגת הודעות באפליקציות חלונאיות תתבצע הרבה פעמים בעזרת MessageBox.
 
 
מתברר (משהו יחסית ישן) שהחברה של sql server פתחו MessageBox משלהם - בטח ראיתם מתי שהוא את החלון הבא: (אם עבדתם עם Sql Server Managment Studio)
 
MessageBox
 
 
לחלון הזה יש כמה פיצ'רים מאוד נחמדים, ראשית הוא נראה הרבה יותר טוב מה - MessageBox הסטנדרטי, בנוסף יש בתחתית החלון אפשרות להעתקת הודעת השגיאה ולחצן נוסף להצגת הפרטים הנוספים:
 
MessageBox
 
 
כדי שתוכלו להשתמש בזה באפליקציות שלכם תצטרכו להוסיף reference ל: Microsoft.NetEnterpriseServers.ExceptionMessageBox (חפשו אותו תחת תיקיית ההתקנה של sql (אצלי הוא יושב ב - C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\1.4)
 
בגרסאות קודמות של sql server (למשל 2005) שם הקובץ היה ExceptionMessageBox.
 
 
לאחר שייבאתם את הקובץ (מומלץ כמובן להגדיר Copy Local=true - כך כשתעבירו את האפליקצייה ללקוח ואין לו sql server האפליקצייה עדיין תעבוד)
 
תוכלו לכתוב קוד כזה:
 

internal static void Show(Exception e)

{

    ExceptionMessageBox emb = new ExceptionMessageBox(e);

    emb.Caption = "Error";

    emb.Symbol = ExceptionMessageBoxSymbol.Error;

    emb.Show(null);

}

 
 
אפשר לתת ב - ctor גם טקסט חופשי, וכמובן להגדיר את ה - symbol המתאים - מתוך הרשימה הבאה:
 

    public enum ExceptionMessageBoxSymbol

    {

        None = 0,

        Warning = 1,

        Information = 2,

        Error = 3,

        Stop = 3,

        Exclamation = 4,

        Asterisk = 5,

        Question = 6,

        Hand = 7,

    }

 
ואפשר אפילו להגדיר בקלות CustomSymbol.
 
בנוסף ניתן להגדיר עד חמשה לחצנים שונים עם הגדרה מה יהיה כתוב אליהם.
 
פיצ'ר נוסף הוא ההגדרה האם יוצג CheckBox שניתן לכתוב עליו כל מה שתרצו (למשל "אל תציג שוב") ותוכלו לקבל את הערך שהמשתמש בחר בפעם הקודמת (זה נשמר ב - registry - אתם יכולים לקבוע את ה - key עבורו)
 
פיצ'ר נוסף היא תמיכה מובנת בשפות עם כתיבה בצד ימין (עברית למשל).
 
 
לסיכום השימוש ב - ExceptionMessageBox עדיף משימוש ב - MessageBox הרגיל ומשדרג את חויית המשתמש.

הפעלת Linq Queries על פקדים המכילים Collections ללא חשיפה של IEnumerable מתאים

 

אחד מהיכולות החזקות של השפה שאנחנו משתמשים בהם רבות זהו היכולת להפעיל Linq to Objects על כל מי שמממש את:
IEnumerable<T>
 
 
ב - windows forms ישנם הרבה פקדים המכילים collections - כמו TabControl, TreeView ועוד.
 
הבעייה עם כל הפקדים הללו שהם חושפים את IEnumerable הרגיל, (ללא T) מה שגורם לכך שאי אפשר להפעיל עליהם שאילתות לינק.
 
 
כדי לתקן זאת ניתן להוסיף Extension Method מתאים לכל פקד ולהמיר את ה - IEnumerable  לאחד שתומך ב - Generic, לדוגמא:
 

internal static class Extension

{

    internal static IEnumerable<TabPage> AsEnumerator(this TabControl.TabPageCollection collection)

    {

        foreach (TabPage item in collection)

        {

            yield return item;

        }

    }

 

    internal static IEnumerable<TreeNode> AsEnumerator(this TreeNodeCollection collection)

    {

        foreach (TreeNode item in collection)

        {

            yield return item;

        }

    }

}

 
 
בשביל הדוגמא - נניח שיש לי TreeView המכיל שמות של טבלאות וכל טבלה מכילה את שמות העמודות (כמו ב - Sql Server Managment Studio)
כעת אני מעוניין לייצר סקריפט עבור שאילתת select - נוכל לכתוב את הקוד הבא:
 
 

string.Format("SELECT {0} FROM {1}",

    treeView1.SelectedNode.Nodes.AsEnumerator()

            .Select(x => "[" + x.Text + "]")

            .Aggregate((x, y) => x + ", " + y),

    treeView1.SelectedNode.Text);

 
התוצאה של הקוד הקודם תהיה:
 

SELECT [Account_Id], [Loyalty_Id] FROM AccountLoyalties

 
 
 
ברגע שנוסיף את  ה - Extension Method הללו עבור הפקדים השונים, נשדרג אותם ונוכל להפעיל עליהם שאילתות Linq

Visual Studio 2010 Icons

 

הרבה פעמים אנחנו מפתחים אפליקציות קטנות (או גדולות) ואנחנו מחפשים אייקונים נכונים לתפריטים.
 
מצאתי שתחת הנתיב:
C:\Program Files\Microsoft Visual Studio 10.0\Common7\VS2010ImageLibrary\1033
יש את רוב האייקונים ש - visual studio משתמש בהם,
 
כל מה שצריך לעשות הוא לחלץ את התייקיה ונקבל את רשימת התיקיות הבאות:
 
_Common Elements
Actions
Animations
Annotations_Buttons
Objects
בתיקיות אלו יש מגוון גדול של האייקונים בגדלים ובפורמטים שונים.
 
תהנו.

דוגמא בסיסית לכתיבה ל - azure blob

 

חבר ביקש שאכתוב לו דוגמה בסיסית לכתיבה וקריאה ל - azure.
 
 
ראשית כמובן יהיה לנו פרוייקט azure כלשהו (Web Role, Worker Role) 
 
לאחר מכן נוכל לכתוב את הקוד הבא:
 
 

var storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));

 

CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

CloudBlobContainer blobContainer = blobClient.GetContainerReference("CONTAINER_NAME");

blobContainer.CreateIfNotExist();

 

 

CloudBlob blob = blobContainer.GetBlobReference("URI or FILE_NAME");

 
 
השורה הראשונה נותנת לנו גישה לחשבון המתאים.
 
(חשוב כמובן להגדיר במאפיינים של פרוייקט ה - azure ולהוסיף את ה - DataConnectionString, (זה נמצא תחת תיקיית Roles במאפיינים של הפרוייקט המתאים בטאב Settings)
עבור מצב Loacl יכול להיות מוגדר עם UseDevelopmentStorage=true
עבור cload צריך לכתוב את הנתיב המלא, יראה משהו כמו:
 
DefaultEndpointsProtocol=http;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY
 
את הערך עבור AccountKey ניתן למצוא באתר הניהול של azure )
 
 
לאחר מכן נקבל הפנייה ל - container ונייצר אותו עם עדיין הוא לא קיים.
 
בשלב הבא נקבל הפנייה ל - blob עצמו, ונוכל להשתמש בפונקציות שונות כמו UploadText, UploadStream וכמובן DownloadText וכו'.
Posted: Nov 22 2011, 10:43 AM by Shlomo | with no comments
תגים:,

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

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

עצלנות של מפתחים ואבטחת מידע - והפעם שימוש ב - reflector

 

בפוסט הקודם תיארתי כיצד לעקוף את הבדיקה של טלריק האם המוצר נקנה או שהוא גרסת ניסיון - על הדרך הבטחתי לספר איך להשתמש ב - reflector.
 
אמנם פוסט זה לא כל כך קשור לאבטחת מידע (או לעצלות של מפתחים) אבל הוא דומה לפוסט הקודם.
 
 
ה - reflector הוא אחד מהכלים המדהימים ביותר שיצאו אי פעם כדי לעזור למפתחים, לצערי הרב מתי שהוא הם החליטו לגבות כסף על התוכנה (35$ לגרסה הבסיסית ו - 95$ לגרסה המלאה).
 
 
כרגיל אני אדגיש שאני חלילה לא מעודד לגנוב אותם, אלא רק מראה עד כמה חשוב לכתוב קוד נכון.
 
במידה ויש לכם את הגרסה הקודמת שלהם (כלומר מלפני שהם החליטו לקחת כסף), כל מה שתצטרכו לעשות כדי להשתמש בו מבלי שהוא יכריח אתכם לקנות אותו, זה להזיז את התאריך של המחשב אחורה - כך שהוא יחשוב שעדיין יש לכם זמן.
 
 
אני יכול ללמד זכות על מי שפיתח את הכלי - שכנראה הם לא חשבו שאי פעם הם יקחו כסף עליו - לכן הם לא חשבו לכתוב מנגנון קצת יותר מתוחכם.
 
 
ואם אני מזכיר את הנושא מצאתי דרך אגב שיש תחליף חינמי מבית טלריק בשם JustDecompile שממבט ראשון הוא נראה מתחרה לא רע של ה - reflector

עצלנות של מפתחים ואבטחת מידע - והפעם כיצד לעקוף את הבדיקה שטלריק עושים האם קניתם את המוצר

 

בפוסט הקודם הראיתי עד כמה מפתחים לא חושבים מספיק על כל הנושא של אבטחת מידע.
 
היום אני אראה משהו דומה ונראה עד כמה מפתחים כותבים לפעמים בצורה מגוכחת.
 
 
אחד הכלים החשובים ביותר בכל סביבת פיתוח - היא הפקדים של טלריק, בכל סביבה שבה אני עובד (win form, web, wpf, silverlight) אני משתדל שיהיה לי את היכולת להשתמש בפקדים שלהם.
 
כמובן שהפקדים עולים כסף (ובכלל לא זול - בסביבות 1000$ עבור סביבה אחת - אבל זה שווה כל שקל), חשוב שיהיה ברור שאני לא מעודד לגנוב אותם חלילה - מטרתי בפוסט זה היא רק להראות עד כמה חשוב לכתוב קוד נכון.
 
בימים אלו יצא לי לראשונה להשתמש בחבילה של wpf controls שלהם, ובכל הפעלה של האפליקצייה קבלתי את ההודעה המעצבנת הבאה:
 
 
telerik trial
 
 
באיזשהו שלב בזמן הפיתוח נמאס לי לקבל את הודעת השגיאה - התחלתי לחפש ב - reflector (שגם איתו יש סיפור מצחיק - בהמשך אספר) איפה הם עושים את הבדיקה האם להציג את הודעת השגיאה, אחרי כרבע שעה של שיטוטים מצאתי את הקוד הבא:
 
 

internal static void Verify(FrameworkElement targetControl)

{

    if ((!IsInDesignMode &&

        (Application.Current != null)) &&

        (Application.Current.Resources["Telerik.Windows.Controls.Key"] == null))

    {

        VerifyImpl(targetControl);

        AssemblyProtection.Validate();

    }

}

 
הם קוראים לפונקצייה בכל ctor של פקד.
 
כל מה שהייתי צריך לעשות כדי להפסיק לקבל את ההודעה הוא להוסיף את הקוד הבא:
 

<Application.Resources>

    <my:String x:Key="Telerik.Windows.Controls.Key">someKey</my:String>

</Application.Resources>

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

דוגמאות בסיסיות לשימוש בשיטות השונות בגישה לבסיס נתונים

 

קבלתי שאלה כיצד מתחברים לבסיס נתונים ב - net.
 
כמובן שהפתרון גדול מידי עבור מסגרת הזו, אבל בכל זאת אני אדגים כאן את הבסיס להתחברות בכל השיטות.
חשוב לזכור שפוסט זה הינו דוגמא בסיסית ביותר לגישה בכל השיטות ולא לימוד מעמיק של כל אחת מהם.
 
(אני מתנצל מראש שהדוגמאות בפוסט זה הם ב - vb.net ולא ב - #C)
 
 
 
הקדמה: 
כדי לגשת לבסיס נתונים מ - net קיימים (בעיקר) שלוש דרכים.
 
הראשונה והבסיסית היא כמובן ado.net.
 
השנייה היא גישה בעזרת dataset, typed dataset.
 
והשלישית היא orm כשהשיטות העיקריות הם nhibernate, entity framework.
 
 
ado.net:
ado.net היא השיטה הבסיסית שכל השיטות מאחורי הקלעים עובדים איתה, מדובר על פתיחת חיבורים לבסיס הנתונים, שליחה של פעולות (select, update, insert, delete) וניתוח התוצאות החוזרות מהשאילתא בעצמנו.
 
 
דוגמא בסיסית לקריאה וכתיבה לבסיס נתונים בעזרת ado.
 
בהנתן שיש לנו טבלה בשם names שנראית כך:
 
 
Names table
 
 
נכתוב טופס שיודע להציג ולהוסיף שמות:
 
form
 
 
כעת נכתוב את הקוד שטוען את כל השמות מבסיס הנתונים ב - ado
 
 

    Private Sub FillCombo()

        ComboBox1.Items.Clear()

 

        Dim cnn As New SqlConnection()

        cnn.ConnectionString = "Data Source=.\SQLEXPRESS;" +

                                "AttachDbFilename=|DataDirectory|\DatabaseDemo.mdf;" +

                                "Integrated Security=True;User Instance=True"

 

        Dim cmd As New SqlCommand()

        cmd.Connection = cnn

        cmd.CommandText = "select [Name] from names"

 

        cnn.Open()

 

        Dim reader As SqlDataReader = cmd.ExecuteReader()

        While reader.Read()

            ComboBox1.Items.Add(reader(0).ToString())

        End While

 

        cnn.Close()

    End Sub

 
ראשית ננקה את ה - combo מהנתונים שיש בו.
לאחר מכן נייצר מופע של SqlConnection ונגדיר לו את ה - ConnectionString - שזה הכתובת היכן בסיס הנתונים יושב.
 
נגדיר אובייקט מסוג SqlCommand ונגדיר לו את ה - Connection ואת ה - Command - שהיא מה השאילתא שנרצה להריץ.
 
כעת אנחנו פותחים את ה - Connection ולאחר מכן נפעיל את פונקצית ExecuteReader - שמחזירה אובייקט מסוג SqlDataReader - שיודע לקרוא את הנתונים מתוצאות השאילתא.
 
כמובן שנזכור לסגור את ה - Connection.
 
 
באירוע Load של הטופס נקרא לפונקציה FIllCombo.
 
 
בנוסף בקוד של הלחצן הוספת שם חדש, נכתוב את הקוד הבא:
 
 

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Dim cnn As New SqlConnection()

        cnn.ConnectionString = "Data Source=.\SQLEXPRESS;" +

                                "AttachDbFilename=|DataDirectory|\DatabaseDemo.mdf;" +

                                "Integrated Security=True;User Instance=True"

 

        Dim cmd As New SqlCommand()

        cmd.Connection = cnn

        cmd.CommandText = "insert into names values(@name)"

        cmd.Parameters.AddWithValue("name", TextBox1.Text)

 

        cnn.Open()

        cmd.ExecuteNonQuery()

        cnn.Close()

 

        FillCombo()

    End Sub

 
עד השורה של הגדרת ה - CommandText הקוד זהה לפונקציה הקודמת.
 
הגדרת ה - CommandText - מגדירה שאילתת Insert עם שימוש בפרמטר בשם name (אפשר היה לשרשר את הערך מתיבת הטקסט - אבל זה גורם לבעיית אבטחה בשם Sql Injection)
 
אחרי שה - Connection נפתח נשתמש ב - ExecuteNonQuery מכיוון שהפעם אנחנו שולחים שאילתא שהיא לא Select.
 
כמובן שבקוד בסביבה אמיתית נדאג לכך שלא נצטרך לשכפל קוד ושהערך של ה - ConnectionString יהיה בקובץ קונפיג ולא בקוד.
 
 
dataset:
חלופה ותיקה של עבודה עם ado.net הסטנדרטי זה עבודה עם dataset - dataset מייצג בזיכרון database ומכיל אובייקטים מסוג datatable, datacolumn, datarow וכן הלאה המייצגים בזיכרון מידע מבסיס הנתונים.
 
ישנם שני סוגים של עבודה עם dataset, הראשונה dataset רגיל שבו נעבוד עם שמות הטבלאות והעמודות בעזרת indexer של שמות, כלומר נוכל לראות קוד כזה:
 
DataTable table = set["tableName"];
 
 
השיטה העדיפה היא עבודה עם Typed dataset - בו נגדיר מראש את הטבלאות וסביבת העבודה תייצר עבורנו מחלקות עבור כל טבלה, לדוגמא נוכל לראות קוד כזה:
 
NamesDataTable table = set.Names;
 
ראשית נוסיף לפרויקט קובץ מסוג dataset - נגדיר לו שם כלשהו (בדוגמא - dataset1)
מה - server explorer נגרור את הטבלה שלנו.
 
בסוף התהליך זה יראה כך:
 
dataset
 
כפי שאפשר לראות - נוצר טבלה בשם Names ובנוסף NamesTableAdapter שתפקידו להריץ את השאילתות עבור ה - dataset.
 
כעת נראה את הקוד שלנו (שיהיה הרבה יותר פשוט)
 

    Dim ds As DataSet1

    Dim adpter As NamesTableAdapter

 

    Private Sub Form3_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        FillComboBox()

 

        ComboBox1.DataSource = ds.Names

        ComboBox1.DisplayMember = "Name"

 

    End Sub

 

    Private Sub FillComboBox()

        ds = New DataSet1()

        adpter = New NamesTableAdapter()

 

        adpter.Fill(ds.Names)

    End Sub

 

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        ds.Names.AddNamesRow(TextBox1.Text)

        adpter.Update(ds.Names)

    End Sub

 
ראשית יש לנו הגדרה של אובייקט מסוג DataSet1 ו - NamesTableAdapter.
 
במתודת FillComboBox ניצור מופע חדש שלהם, ונשתמש במתודה מיוחדת של ה - adapter בשם Fill שמקבל כפרמטר את הטבלה שלתוכה הוא צריך למלאות את הנתונים.
 
באירוע Load, לאחר הקריאה למתודה, ניתן את הטבלה כפרמטר ל - DataSource של ה - Combo ונגדיר איזה עמודה תוצג.
 
בלחיצה על הוספה, נוסיף שורה חדשה לטבלה ונפעיל את פונקציית Update כדי לשמור בבסיס הנתונים.
 
 
 
orm:
object relations mapping הינו רעיון המדבר על עבודה עם אוביקטים בלי לחשוב (כמעט) על בסיס נתונים. ההבדל המרכזי (ברעיון ולא בטכנולוגיה) בינו לבין dataset, שב - dataset אנחנו עובדים ומדברים על מושגים של טבלאות שורות ועמודות, לעומת orm שבו אנחנו עובדים עם אובייקטים ו - object oriented.
 
יש כמה מימושים ל - orm, הותיקה ביותר היא nhibernate, והטובה ביותר (לדעתי) היא entity framework.
 
נראה דוגמא לעבודה עם entity framework.
 
נוסיף קובץ מסוג ADO.Net Entity Data Model (סיומת edmx)
 
יפתח wizard שישאל האם אנחנו רוצים מודל ריק או מודל שיווצר מבסיס הנתונים, נבחר מבסיס הנתונים, לאחר מכן הוא יבקש את ה - Connection String ואת הטבלאות שנרצה להוסיף.
 
בסוף התהליך נקבל את הדבר הבא:
 
edmx
 
כעת נוכל לכתוב את הקוד הבא:
 

    Dim context As New DatabaseDemoEntities()

 

    Private Sub Form4_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        ComboBox1.DataSource = context.Names

        ComboBox1.DisplayMember = "Name"

    End Sub

 

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        context.Names.AddObject(NameObject.CreateNameObject(0, TextBox1.Text))

        context.SaveChanges()

        ComboBox1.DataSource = context.Names.ToArray()

    End Sub

 
באירוע Load ניתן את המאפיין Names כמקור מידע ל - ComboBox.
ובפונקצית Add נוסיף אוביקטים חדשים.
 
 
לסיכום:
אין שיטה נכונה יותר או נכונה פחות לעבודה עם בסיס הנתונים, כל השיטות הם נכונות - השאלה היא מהו הפרויקט ועל מה מדובר. ההחלטה כיצד לדבר עם בסיס הנתונים היא החלטה שצריך לחשוב עליה ולא להחליט כלאחר יד.
 
מהנסיון שלי - העבודה הכי פשוטה וקלה היא שיטת orm עם Entity Framework 4.0 (הגרסאות שלאחר מכן הם יותר מסובכות ומתאימות לפרוייקטים גדולים יותר שעובדים עם ארכיטקטורות מסוימות).
 
 
כמובן פוסט זה הוא רק נגיעה בכל אחת מהשיטות, ולא משנה מה תבחרו תצטרכו להעמיק בנושא כדי לדעת לכתוב ולעבוד בצורה נכונה.

עצלנות של מפתחים ואבטחת מידע

 

קיימים הרבה גורמים לבעיות באבטחת מידע אבל אחד מהגורמים העיקריים לבעיות אלו זה אנחנו - המפתחים - לפעמים אנחנו לא מודעים (או מתעצלים להיות מודעים) לכתיבה של קוד נכון שיהיה מאובטח לפחות ברמה מינימלית.
 
חבר הראה לי משחק טריוויה באתר נענע בשם "לעוף על המליון" - אני לא משחק במחשקי מחשב בכלל, אבל כשהוא הראה לי את המשחק ה - Fiddler היה פתוח (אני מאוד מקווה שאתם מכירים את הכלי הזה - אחרת רוצו ללמוד אותו).
 
בכל מקרה, הצצתי על הפידלר ולתדהמתי אני רואה שבכל פעם שיש שאלה חדשה נשלח כמובן Request עם בקשה לשאלה חדשה, והנה ה - Response
 
nana
 
 
אני מקווה שאתם מצליחים לראות - אם לא תפתחו Fiddler ותווכחו שעל כל שאלה הם שולחים ללקוח גם את התשובה.
 
מדהים עד כמה הבאג הזה נובע מעצלות (או מאי מודעות) - בסך הכול היה צריך לשלוח את השאלה לשרת ושם לבצע את הבדיקה - או שהם יוצאים מתוך הנחה שמתכנתים וחובבי אבטחת מידע לא מתעניינים בשטויות אלו.
 
למען האמת - קצת הצטערתי שלא מדובר על משחק בכסף אמיתי, כך יכולתי לבוא לנענע ולבקש מהם תשלום על ייעוץ באבטחת מידע (לא שאני מבין גדול בנושא) -:)
 
 
מה שאני רוצה להשיג בפוסט זה הוא - שנפנים שאת הקוד שאנחנו כותבים צריך לכתוב במינימום של מחשבה גם על אבטחת מידע.

מה לעשות כששימוש עם UrlRoutingHandler לא עובדת תחת IIS

 

בעבר כתבתי על היכולת לייצר מנגנון URL Shortcut בשימוש עם UrlRoutingHandler.
 
לפעמים הקוד במחלקה עובד רק כשעובדים עם השרת הפנימי של visual studio, אבל כשעוברים לעבוד מול IIS, הקוד מפסיק לעבוד.
 
 
נקח לדוגמא את הקוד הבא:
 
 

public class RoutingHandler : UrlRoutingHandler, IRouteHandler

{

    public string Url { get; set; }

 

    protected override void VerifyAndProcessRequest(IHttpHandler httpHandler, HttpContextBase httpContext)

    {

            httpContext.Response.Redirect(Url);

    }

 

    public IHttpHandler GetHttpHandler(RequestContext requestContext)

    {

        return this;

    }

}

 
הקוד הזה יאפשר לנו להשתמש במנגנון ה - Routing גם באפליקציות asp.net web forms עבור קבצי html.
 
לדוגמא נוכל לכתוב ב - application start את הקוד הבא:
 

RouteTable.Routes.Add("login",

        new Route("login",

            new RoutingHandler()

            {

                Url = "~/Managment/login.htm"

            }));

 
 
מה שאומר, שאם נגלוש בצורה הבאה: http://domain.com/login נגיע אוטומטית ל - http://domain.com/managment/login.htm
 
(מכיון ששימוש סטנדרטי של RouteTable.Routes.MapPageRoute לא עובד עם קבצי htm)
 
 
בכל מקרה הקוד עובד תמיד תחת vs, אבל כשמעלים ל - IIS לפעמים זה מפסיק לעבוד.
 
 
לאחר שיטוט בגוגל, הגעתי לכאן.
מה שצריך לעשות הוא ראשית להוסיף בקונפיג (תחת system.webServer) את הקוד הבא (בהנחה שיש לכם iis 7 ומעלה)
 

<handlers>

  <add name="UrlRoutingHandler"

        preCondition="integratedMode"

        verb="*"

        path="UrlRouting.axd"

        type="LP.Web.RoutingHandler, LP.Web"/>

</handlers>

 
במידה ומותקן לכם על HttpRedirection תצטרכו להוסיף בקונפיג גם את הקוד הבא:
 

<modules runAllManagedModulesForAllRequests="true">

  <remove name="UrlRoutingModule"/>

  <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,

                                      System.Web,

                                      Version=4.0.0.0,

                                      Culture=neutral,

                                      PublicKeyToken=b03f5f7f11d50a3a" />

</modules>

 
כעת הקוד שלכם יעבוד גם על IIS
Posted: Nov 10 2011, 05:51 PM by Shlomo | with no comments
תגים:, ,

Create a template to define an HTML page (using t4 template)

 

הקדמה: 
לאחרונה אני עובד על פרוייקט כלשהו שאחת הדרישות הייתה שבלחיצה על "שמור" יווצר קובץ html סטטי עבור אותו אובייקט, הסיבה לכך היא כמובן ביצועים - בדרך כלל נייצר דף דינמי אחד שמתמלא בתוכן לפי פרמטר ב - query string, במקרה הזה רצו לייצר דף html כדי שהלקוח הסופי יקבל תוצאות מהירות יותר.
 
התלבטתי כיצד לממש את זה, לכן שאלתי את החברים בתפוז לדעתם, קבלתי כמה הצעות, מנהל הפורום זיו הציע לי להשתמש עם t4 template, התחלתי לקרוא על הנושא ודי התלהבתי - הוא נותן יכולות נהדרות שעוזרות לבצע את העבודה די בקלות.
 
 
בפוסט זה אני אעבור צעד אחר צעד - כיצד עובדים עם המנגנון.
 
הורדת הקוד המלא של פוסט זה.
 
נניח שהעבודה היא מול סילבוסים של מכללה (הפרוייקט האמיתי הוא לא - אבל בשביל הדוגמא)
 
 
תחילת העבודה: 
 
נגדיר אובייקט המכיל מידע על סילבוס.
 

public class Syllabus

{

    public string CourseCode { get; set; }

    public string Title { get; set; }

    public float Version { get; set; }

    public string Description { get; set; }

    public DateTime[] OpenDays { get; set; }

    public string[] Topics { get; set; }

    public int Days { get; set; }

}

 
כפי שאפשר לראות האובייקט מכיל מידע כמו כותרת, גרסה, תאריכים שנפתחים, נושאים ועוד.
 
כעת נכתוב מתודה שאמורה להחזיר את הסילבוס מבסיס הנתונים (בשביל הדוגמא נכתוב מתודה שמחזירה סילבוס סטטי)
 
 

private static Syllabus GetSyllabusFromDb(string courseCode)

{

    return new Syllabus()

    {

        CourseCode = courseCode,

        Description = @"This six-day instructor-led course provides students with the knowledge and skills to

                        develop applications in the .NET Framework 4.0 using the C# 4.0 programming language.

                        C# is one of the most popular programming languages in existence,

                        and the C# 4.0 revision introduces new productivity,

                        performance, and convenience features into the language.

                        This course features an overview of all language-related features,

                        as well as an introduction to general .NET Framework features such as garbage collection,

                        assembly loading, Reflection, Language-Integrated Query (LINQ) and many others",

        OpenDays = new DateTime[]

        {

            DateTime.Now.AddDays(3),

            DateTime.Now.AddDays(10),

            DateTime.Now.AddDays(20)

        },

        Title = "C# 4.0 Programming in the .NET Framework",

        Topics = new string[]

        {

            "Introduction to the .NET Framework",

            "Introduction to C# 4.0",

            "The .NET Type System",

            "C# Classes",

            "Garbage Collection"

        },

        Version = 1.3F,

        Days = 6

    };

}

 
(את המידע לקחתי מהסילבוס של סלע על C# 4.0)
 
 
הגדרת התוצר הסופי: 
 
כעת נרצה להריץ קוד שיודע לייצר קובץ html עם מבנה מוגדר מראש עבור התוכן.
 
מומלץ לקרוא את התיעוד ב - msdn מאמר ראשון, מאמר שני.
 
הדרך הקלה והפשוטה לעשות זאת היא להתחיל עם כתיבת טופס html שיראה כפי שנרצה שהתוצאה הסופית תראה.
 
נוסיף קובץ html לפרוייקט, נקרא לו SyllabusTemplate.html, ונתחיל לערוך אותו בהתאם למבנה של קובץ ה - html שנרצה לקבל בסוף התהליך.
 
 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

<head>

<title>COURSE_CODE version VERSION</title>

        <style>

            body

            {

                font-family:Arial;

                font-size:14px;

            }

            .header

            {

                text-align:center;

            }

            .header h1

            {

                font-size:19px;

                font-weight:bold;

            }

            span

            {

                color:Blue;

                font-weight:bold;

            }

            ul

            {

                padding-right:10px;

            }

        </style>

</head>

<body>

    <div class="header">

            <h1>TITLE</h1>

            <h4>DAYA days course</h4>

        </div>

        <div class="desc">

            <span>Description</span>

            <p>DESCRIPTION</p>

        </div>

        <div class="topics">

            <span>Topics</span>

            <ul>

                <li>TOPIC</li>

                <li>TOPIC</li>

                <li>TOPIC</li>

                <li>TOPIC</li>

            </ul>

        </div>

        <div class="days">

            <span>Dates</span>

            <ul>

                <li>DAY</li>

                <li>DAY</li>

                <li>DAY</li>

            </ul>

        </div>

</body>

</html>

 
כעת אחרי שהחלטנו כיצד נרצה שדף ה - html ייראה, נרצה להפוף את הדף ל - template.
 
 
הגדרת הקובץ ועבודה עם t4 template:
 
הדבר הראשון שנעשה הוא לשנות את הסיומת של הקובץ מ - html ל - tt.
 
לאחר מכן במאפייני הקובץ (על ידי לחיצה על F4 כשהקובץ מסומן ב - Sulotion) יש לוודא שהערך TextTemplatingFilePreprocessor נמצא במאפיין CustomTool (יש לשים לב שהרבה פעמים יהיה שם הערך TextTemplatingFileGenerator -
 
זה יכול לקרות בתהליך שכרגע תיארתי - כלומר שינוי הסיומת של קובץ לסיומת tt - במקרה זה יש להחליף לערך הנכון.
 
במקרה שתוסיפו לפרוייקט מלכתחילה קובץ מסוג Preprocessed Text Template הוא יקבל את הערך הנכון - אני חושב שעדיף לעבוד ראשית עם קובץ רגיל כדי להגדיר את התוצאה הסופית ורק בסוף התהליך לשנות את הסיומת ל  - tt)
 
 
כעת תוכלו לראות שתחת קובץ tt נוצר קובץ בשם SyllabusTemplate.cs המכיל partial class בשם SyllabusTemplate עם מתודה אחת בשם TransformText אשר נשתמש בה בהמשך כדי לייצר את הקובץ, נוסף על כך יש מחלקה בשם SyllabusTemplateBase עם מתודות שיעזרו לנו בהמשך לכתוב את ה - template בצורה הנכונה.
 
הדבר הראשון שנרצה לעשות מן הסתם היא להכיר בין ה - SyllabusTemplate ל - Syllabus כדי שקובץ ה - html יווצר דינמית לפי תוכן האובייקט.
 
לכן נוסיף ctor למחלקה SyllabusTemplate בעזרת יכולות ה - partial class.
 

public partial class SyllabusTemplate

{

    public Syllabus Syl { get; private set; }

 

    public SyllabusTemplate(Syllabus syllabus)

    {

        Syl = syllabus;

    }

}

 
כעת אנו בטוחים שה - template מכיל מופע של Syllabus. (באותו צורה ניתן להוסיף מתודות ומאפיינים משלנו שנוכל להשתמש בהם בקובץ ה - template).
 
נוסיף בשורה הראשונה של הקובץ את הקוד הבא: 
 
<#@ template language="C#" #>
 
התחביר מאוד דומה לקוד צד שרת שאנחנו כותבים בדפי aspx, השורה שהגדרנו נקראת Directives המגדירה שהקוד בקובץ ה - template יהיה בשפת #C.
 
מה שנעשה עכשיו הוא לקחת את כל המידע שאמור להיות דינמי ונכתוב אותו בעזרת האובייקט Syl.
 
ניקח לדוגמא את ה - title בקובץ שכתוב כרגע כך:
 

<title>COURSE_CODE version VERSION</title>

 
נחליף אותו עם:

<title><#= string.Format("{0} version {1}", Syl.CourseCode, Syl.Version) #></title>

 
הסימנים מאפשרים לנו לכתוב קוד #C, הקטע הזה נקרא Expression control blocks המאפשר לנו לכתוב שורת קוד אחת (בלי צורך בנקודה פסיק בסוף המשפט)
 
נמשיך עם מקטע העיצוב, כדי שקובץ ה - template לא יהיה ארוך נשמח להוציא אותו לקובץ נפרד,
נייצר קובץ css ונעתיק לשם את כל ה - style.
 
כעת בקובץ ה - tt נכתוב את הקוד הבא:
 

<style>

    <#@include file="Stylesheet.css" #>

</style>

 
ה - Directives של Include מאפשר לנו לייבא תוכן מקובץ חיצוני.
 
נמשיך ונשנה את המקטע הבא:

<h1>title</h1>

ל -

<h1><#= Syl.Title #></h1>

 
נמשיך ונשנה את המקטע הבא:
 

<h4>DAYA days course</h4>

ל -

<h4><#= Syl.Days #> days course</h4>

 
נעשה אותו דבר עם השדה Description.
 
כעת ב - Topics נרצה לבצע איטרציה על כל ה - Topics, נכתוב את הקוד הבא:
 

<div class="topics">

    <span>Topics</span>

    <ul>

         <# foreach(string topic in Syl.Topics)

         {

             WriteLine(string.Format("<li>{0}</li>", topic));

         }#>

    </ul>

</div>

 
במקרה הזה היות שאנחנו כותבים יותר משורת קוד אחת נשתמש ב - Control Block ונכתוב קוד #C רגיל.
פונקציית WriteLine היא אחת מ - Helpers שאנחנו מקבלים.
 
אותו דבר נעשה גם עם התאריכים - אבל בשיטה אחרת:
 

<div class="days">

    <span>Dates</span>

    <ul>

        <# foreach(DateTime day in Syl.OpenDays)

           { #>

               <li><#= day.ToString() #></li>

        <# } #>

    </ul>

</div>

 
 
כעת כל מה שנשאר לעשות הוא להריץ את הקוד הבא:
 

Syllabus syl = GetSyllabusFromDb("50105B");

SyllabusTemplate template = new SyllabusTemplate(syl);

 

string content = template.TransformText();

File.WriteAllText(syl.CourseCode + ".html", content);

 
 
כתוצאה נקבל קובץ בשם 50150B.html עם התוכן כפי שציפינו.
 
 
סיכום:
 
פוסט זה מסביר את הבסיס לעבודה עם t4 template יש עוד מספר דברים שלא עברתי אליהם במסגרת זו - כמו עבודה עם base class הוספת מתודות ועוד, כפי שאמרתי מומלץ לעבור על התיעוד ב - msdn, עם כל זאת לאחר קריאת פוסט זה יש לכם את הכלים להתחיל לעבוד עם הכלי הזה.
 
כדי לראות דוגמא ל - t4 template מורכב, הוסיפו קובץ של Entity Framework (סיומת edmx) ייצרו מודל כלשהו עם כמה entities וקשרים, ואז לחיצה ימנית על המודל ובחרו ב - Add Code Generation Item ובחרו ב - DbContext, כעת יווצר קובץ tt עם הרבה קוד שכדאי לקרוא אותו ולהחכים.

החשכת המסך בזמן פניית ajax של jquery

 

(ושוב תודה לחיים בריקמן - על השיתוף)
 
לרוב כשאנו עושים פעולת ajax נרצה לתת למשתמש אינדקציה שמשהו קורה, בג'ימל אנו מקבלים הודעת Loading בצהוב בראש העמוד, כשעובדים עם Update Panel יש Control שעושה את העבודה בצורה אוטומטית.
 
כאן נראה כיצד ניתן להחשיך את המסך ולהציג במרכזו אנימציה בזמן פניית ajax.
 
(כאן הדגמתי כיצד לעשות זאת ידנית - בזמן לחיצה על כפתור)
 
 
בקובץ js מרכזי (שכל הדפים מכילים אותו) נכתוב את הקוד הבא:
 

$.ajaxSetup({

    beforeSend: function () {

        var $window = $(window);

        var $body = $('body');

 

        $body.css('cursor', 'wait');

        var $loadingOverlay = $('<div />').addClass('loading_overlay')

                                          .css({

                                              width: $window.width(),

                                              height: $window.height()

                                          });

 

        $body.prepend($loadingOverlay);

    },

    complete: function () {

        var $body = $('body');

 

        $body.css('cursor', 'default');

        $body.find('div.loading_overlay').remove();

    }

});

 
ה - ajaxSetup נותן לנו להגדיר הגדרות כלליות אודות בקשות ה - ajax שלנו (וזה לא משנה האם השתמשנו ב - get, post, load וכו').
 
נוסיף פונקציה ל - beforeSend שתוסיף בתחילת העמוד div ריק שיקבל css כלשהו (שמיד נראה אותו) ובנוסף יקבל את הרוחב והגובה של החלון, וכמובן נגדיר שהמצביע יהיה "המתנה".
 
בזמן complete (בסיום קריאת ajax) נוריד את ה - div, ונחזיר את המצביע.
 
 
קוד ה - css
 

.loading_overlay

{

    position: absolute;

    float: left;

    z-index: 99999;

    opacity: 0.7;

    -moz-opacity: 0.7;

    filter:alpha(opacity=70);

    background-color: #ffffff;

    background-image: url('../img/icons/ajax_loading.gif');

    background-repeat: no-repeat;

    background-position: center center;

}

 
 
הגדירו כמובן תמונה מסוג animated gif שתשב במקום המתאים.

VisualStudio 2010 JavaScript & CSS Outlining - AddIn חובה לכל מפתח WEB

 

כל מי שמפתח Web ב - Visual Studio מתי שהוא כנראה "ברך" את מייקרוסופט למה אין את האופצייה של כיווץ פונקציות בקבצי java script, וחלוקה לקטעי region.
 
לא עוד.
 
התקינו את ה - AddIn הבא http://jsoutlining.codeplex.com/, ותהנו מחיי פיתוח טובים יותר.
 
הוא מכווץ כל פונקציה, וכל משפט המתפרש על יותר משורה אחת (פקודות if ופונקציות אנונימיות וכדו')
 
נוסף על כך ניתן להוסיף קטעי region על ידי כתיבה כזו:
 
//#region RegionName
 
 
//#endregion
 
 
תהנו