מדריך CSHTML

מדריך CSHTML – יסודות כתיבת קוד בצד שרת

‏ • John Bryce

עבודה עם נתיבי קבצים ותיקיות בתוך קוד

לעתים קרובות נשתמש בנתיבי קבצים ותיקיות בקוד. הנה דוגמא של מבנה תיקיות פיזי של אתר אינטרנט העשוי להופיע על מחשב הפיתוח שלך:

 

paths example

 

על שרת אינטרנט, לאתר יש גם מבנה תיקיות וירטואליות המתאים לתיקיות הפיזיות באתר. כברירת מחדל, שמות תיקיות וירטואליות זהים לשמות התיקיות הפיזיות. שורש התיקיות הווירטואלי מיוצג בקו נטוי (/), בדיוק כמו שתיקיית השורש של כונן C: במחשב מיוצגת על ידי קו נטוי הפוך (\).

הנה נתיבים פיזיים ווירטואליים עבור הקובץ Styles.css מהמבנה הנ"ל:

  • נתיב פיזי:    C:\WebSites\MyWebSiteFolder\styles\Styles.css
  • נתיב וירטואלי:   styles/Styles.css

האופרטור ~ : שליפת השורש הוירטואלי

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

 

@{
  var myImagesFolder = "/images";
  var myStyleSheet = "/styles/StyleSheet.css";
}

 

הפונקציה Server.MapPath: המרת נתיב וירטואלי לנתיב פיזי

הפונקציה Server.MapPath ממירה נתיב וירטואלי (כמו /default.cshtml) לנתיב פיזי מוחלט (כמו C:\WebSites\MyWebSiteFolder\default.cshtml).

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

 

@{
  var dataFilePath = "/dataFile.txt";
}
<!— C:\Websites\MyWebSite\datafile.txt
מציג את הנתיב הפיזי --
>
<
p>@Server.MapPath(dataFilePath)</p
>

הפונקציה href: יצירת נתיבים למשאבים באתר

הפונקציה Href של האובייקט WebPage ממירה נתיבים שתיצור בקוד השרת (אשר יכולים לכלול את האופרטור ~) לנתיבים שהדפדפן מבין (הדפדפן לא יכול להבין את האופרטור ~, כי זהו אופרטור של CSHTML).

ניתן להשתמש בפונקציה Href כדי ליצור נתיבים למשאבים כגון קבצי תמונה, דפי אינטרנט אחרים וקבצי CSS.

לדוגמה, תוכל להשתמש בפונקציה זו בתגיות ה-HTML עבור תכונות של תגיות <img>, תגיות <link> ותגיות <a>.

 

 

<!-- "../images/Logo.jpg" יוצר את הנתיב: -->
<img src="@Href(myImagesFolder)/Logo.jpg" />
 
<!—אותו דבר, תוך שימשו באופרטור ~   --> 
<img src="@Href("/images")/Logo.jpg" />
 
<!— CSS  קישור לקובץ --> 
<link rel="stylesheet" type="text/css"
  href="@Href(myStyleSheet)" 
/>

 

לוגיקה מותנית ולולאות

בדיקת תנאי

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

 

@{
  var showToday = true;
  if (showToday)
  {
  @DateTime.Today;
  }
}

 

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

 

@{
  var showToday = false;
  if (showToday)
  {
  @DateTime.Today;
  }
  else
  {
  <text>Sorry!</text>
  }
}

 

ניתן להוסיף תנאים מרובים באמצעות בלוק else if:

 

@{
  var theBalance = 4.99;
  if (theBalance == 0)
  {
  <p>
    You have a zero balance.</p>
  }
  else if (theBalance > 0 && theBalance <= 5)
  {
  <p>
    Your balance of $@theBalance is very low.</p>
  }
  else
  {
  <p>
    Your balance is: $@theBalance</p>
  }
}

 

בדוגמה זו, אם התנאי הראשון של הבלוק if הוא לא נכון, התנאי ב- else if יבדק. אם תנאי זה מתקיים, בלוק הפקודות של else if יופעל. אם אף אחד מהתנאים לא התקיים, בלוק הפקודות האחרון – השייך ל- else יופעל.

ניתן להוסיף כמה בלוקים של else if שנרצה, ולאחר מכן לסיים עם בלוק else המתבצע במקרה שאף תנאי לא התקיים.

כדי לבדוק מספר רב של מצבים, מומלץ להשתמש בבלוק switch :

 

@{
  var weekday = "Wednesday";
  var greeting = "";

  switch (weekday)
  {
    case "Monday":
      greeting = "Ok, it's a marvelous Monday";
      break;

    case "Tuesday":
      greeting = "It's a tremendous Tuesday";
      break;

    case "Wednesday":
      greeting = "Wild Wednesday is here!";
      break;

    default:
      greeting = "It's some other day, oh well.";
      break;
  }
    
  <p>
    Since it is @weekday, the message for today is: @greeting</p>
}

 

המשתנה שנבדק נמצא בסוגריים העגולים של פקודת ה- switch (בדוגמה, המשתנה weekday). כל בדיקה משתמשת במשפט case המסתיימת עם נקודתיים (:). אם ערכו של משפט ה- case מתאים לערך הבדיקה, הקוד בבלוק שלו מתבצע.

ניתן לסגור כל בלוק של case עם פקודת break (אם תשכח להשתמש ב- break, הקוד ב- case הבא גם יתבצע).

לבלוק switch יש בד"כ משפט default בסופו, שבאמצעותו ניתן לכתוב פקודות שיתבצעו במקרה ואף אחד מהבדיקות שב- case השונים לא התקיימו.

התוצאה של שני הבלוקים המותנים האחרונים מוצגת בדפדפן:

 

switch example

 

לולאות (ביצוע חוזר)

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

 

@for (var i = 10; i < 21; i++)
{
  <p style="font-size: @(i + "pt")">
    My font size is now: @i</p>
}

 

הלולאה מתחילה עם מילת המפתח for, ואחריה שלושה חלקים בסוגריים עגולים, בין שלושת החלקים מפרידים באמצעות נקודה פסיק.

· בתוך הסוגריים, הפקודה הראשונה (;var i=10) יוצרת מונה ומאתחלת אותו ל- 10. לא חובה לקרוא למונה i , ניתן להשתמש בכל שם משתנה חוקי. כאשר לולאת for רצה, המונה מתקדם באופן אוטומטי.

· הפקודה השנייה (;i < 21 ) מגדירה את עד כמה אתה רוצה לספור. במקרה זה, אנחנו רוצים להגיע למקסימום של 20 (כלומר, להמשיך את המונה כל עד הוא קטן מ- 21).

· הפקודה השלישית (++i ) משתמשת באופרטור הקידום הגורם למונה של הלולאה (המשתנה i) להתקדם בכל פעם שהלולאה רצה ב- 1.

בתוך הסוגריים המסולסלים יופיע הקוד שיפעל עבור כל איטרציה ("סיבוב") של הלולאה. הקוד בדוגמא שלנו משתמש בתגית <p> על-מנת ליצור פסקה חדשה בכל פעם שהלולאה רצה וקובע את גודל הגופן לערך של המשתנה i . הקוד בדוגמה יוצר 11 שורות המציגות הודעה, כאשר בכל שורה גודל הטקסט גדול יותר מהשורה הקודמת.

 

loop - for example

 

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

הדוגמה הבאה מחזירה את הפריטים מהאוסף Request.ServerVariables (אשר מכיל מידע על שרת האינטרנט שלך). היא משתמשת בלולאת foreach כדי להציג את השם של כל פריט על ידי יצירת תגית <li> חדשה ברשימת תבליטים.

 

<ul>
  @foreach (var myItem in Request.ServerVariables)
  {
    <li>@myItem</li>
  }
</ul
>

foreach היא מילת המפתח ואחריה (בסוגריים עגולים) מצהירים על המשתנה שמייצג פריט אחד באוסף (בדוגמה, var myItem), ואחריה מילת המפתח in, ולסיום שם האוסף שעליו רוצים לעבור. בגוף של לולאת foreach, ניתן לגשת לפריט הנוכחי באמצעות המשתנה שהצהרנו.

 

loop - foreach example

 

כדי ליצור לולאה לשימוש כללי יותר ניתן להשתמש בלולאת while :

 

@{
  var countNum = 0;
  while (countNum < 50)
  {
    countNum += 1;
  <p>
    Line #@countNum:
  </p>
  }
}

 

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

 

אובייקטים ואוספים

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

האוביקט Page

האובייקט הבסיסי ביותר ב- CSHTML הוא הדף (Page). אתה יכול לגשת למאפיינים של אובייקט הדף ישירות, ללא כל אובייקט מקדים. הקוד הבא מקבל את נתיב הקובץ של הדף באמצעות אוביקט Request של הדף:

 

@{
  var path = Request.FilePath;
}

 

כדי לעשות זאת ברור יותר, ניתן להשתמש בקידומת this לשם של הפונקציה/מאפיין. הנה אותה הדוגמא בשילוב מילת המפתח this:

 

@{
  var path = this.Request.FilePath;
}

 

ניתן להשתמש במאפיינים של האוביקט Page כדי לקבל מידע רב, כגון:

  • Request .Request – אוסף של מידע אודות הבקשה הנוכחית, כולל איזה סוג של דפדפן ביצע את הבקשה, כתובת ה-URL של הדף, זהות המשתמש וכו'.
  • Response .Response – אוסף של מידע על התגובה שיישלח לדפדפן עם סיום פעולתו של קוד השרת. לדוגמה, תוכל להשתמש במאפיין זה כדי לכתוב את המידע לתוך התגובה.
 
@{
  // גישה למאפיין הכתובת על-מנת לשלוף את כתובת הדף
  var pageUrl = this.Request.Url;
}
<a href="@pageUrl">My page</a> 

 

אובייקטים של אוסף (מערכים ומילונים)

אוסף (collection) הוא קבוצה של אובייקטים מאותו סוג, כגון אוסף של אובייקט של "לקוח" ממסד נתונים.

שפתCSHTML מכילה הרבה אוספים מובנים, כמו האוסף Request.Files.

לעתים קרובות נעבוד עם נתונים באוסף. שני סוגים נפוצים הם האוספים array (מערך) ו- dictionary (מילון).

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

 

@{
  <h3>
    Team Members</h3>
  string[] teamMembers = { "Matt", "Joanne", "Robert", "Nancy" };
  foreach (var person in teamMembers)
  {
  <p>@person</p> 
  }
}

 

עם מערכים, אתה מצהיר על סוג נתונים ספציפי, כגון string , int , או DateTime . כדי לציין כי המשתנה יכול להכיל מערך, אתה מוסיף סוגריים מרובעים להצהרה עליו (כגון []string או []int ). אתה יכול לגשת פריטים במערך באמצעות המיקום שלהם (האינדקס) או באמצעות לולאת foreach.

האינדקס של המערך מבוסס אפס – כלומר, האינדקס (המיקום) של הפריט הראשון במערך הוא 0, הפריט השני נמצא במיקום ה- 1, השלישי במיקום ה- 2 וכן הלאה.

 

 @{
    string[] teamMembers = {"Matt","Joanne","Robert","Nancy"};
    <p>The number of names in the teamMembers array:
      @teamMembers.Length </p>
    <p>Robert is now in position:
      @Array.IndexOf(teamMembers, "Robert")</p>
    <p>The array item at position 2 (zero-based) is
      @teamMembers[2]</p>

    <h3>Current order of team members in the list</h3>
    foreach (var name in teamMembers)
    {
        <p>@name</p>
    }

    <h3>Reversed order of team members in the list</h3>
    Array.Reverse(teamMembers);
    foreach (var reversedItem in teamMembers)
    {
        <p>@reversedItem</p>
    }
}

 

ניתן לקבוע את מספר הפריטים במערך ידי שימוש במאפיין ה- Length של המערך. כדי לקבל את המיקום של פריט מסוים במערך (כדי לחפש במערך), ניתן להשתמש בפונקציה Array.IndexOf. ניתן גם לבצע פעולות כמו להפוך את התוכן של המערך (הפונקציה Array.Reverse) או למיין את התוכן (הפונקציה Array.Sort).

הפלט של מערך המחרוזות הנ"ל מוצג בדפדפן:

 

Array example

 

המילון (dictionary) הוא אוסף של זוגות המורכבים ממפתח (key) וערך (value), שבו מספקים את המפתח (או את השם) כדי להגדיר או לשלוף את הערך המתאים:

 

@{
  var myScores = new Dictionary<string, int>();
  myScores.Add("test1", 71);
  myScores.Add("test2", 82);
  myScores.Add("test3", 100);
  myScores.Add("test4", 59);
}
<p>
  My score on test 3 is: @myScores["test3"]</p>
@(myScores["test4"] = 79)
<p>
  My corrected score on test 4 is: @myScores["test4"]</p
>

 

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

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

 

myScores["test4"] = 79;

 

כדי לקבל ערך מהמילון, יש לציין את המפתח בסוגריים מרובעים:

 

var testScoreThree = myScores["test3"];

 

קריאה לפונקציה עם פרמטרים

לאובייקטים יכולים להיות פונקציות, לדוגמה, לאובייקט Database יש את הפונקציה Database.Connect. לפונקציות רבות יש פרמטר אחד או יותר. פרמטר הוא ערך שיש להעביר לפונקציה כדי שהפונקציה תוכל לבצע את המשימה שלה. לדוגמה, לפונקציה Request.MapPath יש שלושה פרמטרים:

 

@{ public string MapPath(string virtualPath,
                         string baseVirtualDir,
                         bool allowCrossAppMapping);
}

 

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

דוגמא לקריאה לפונקציה זו  – שים לב לשלושת הפרמטרים שהזנו בסוגריים עגולים לפונקציה MapPath:

 
  var myPathPositional = Request.MapPath("/scripts","/",true);
  <p>@myPathPositional</p
>
 

טיפול בשגיאות – משפטי Try-catch

לעיתים קוד שנכתוב יכול להיכשל בזמן הריצה מסיבות שמעבר לשליטתך, לדוגמה:

· אם הקוד שלך מנסה לפתוח, ליצור, לקרוא, או לכתוב קובץ, כל מיני שגיאות עלולות להתרחש: הקובץ הרצוי לא קיים, הוא יכול להיות נעול, אין הרשאות מספיקות, וכן הלאה.

· בדומה לכך, אם הקוד שלך מנסה לעדכן רשומות במסד נתונים, יכולה להיות בעיית הרשאה, החיבור למסד הנתונים יכול להתנתק, הנתונים שאתה מעונין לשמור לא חוקיים, וכו'.

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

 

error without try/catch

 

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

הדוגמה הבאה מציגה דף היוצר קובץ טקסט על הבקשה הראשונה ולאחר מכן מציג לחצן המאפשר למשתמש לפתוח את הקובץ.

הדוגמה בכוונה משתמשת בשם קובץ שגוי (לא קיים) כדי לגרום לחריגה. הקוד כולל catch עבור שני חריגים אפשריים: FileNotFoundException , אשר מתרחש כאשר הקובץ לא קיים, ו- DirectoryNotFoundException אשר מתרחש אם CSHTML אפילו לא יכול למצוא את התיקייה שמכילה את הקובץ.

אם הקוד שלך לא יטפל בחריג, היית רואה דף שגיאה כמו בצילום מסך הנ"ל. עם זאת, בלוקים של try/catch עוזרים למנוע מהמשתמש לראות סוגים כאלה של טעויות.

 

@{
  var dataFilePath = "/dataFile.txt";
  var fileContents = "";
  var physicalPath = Server.MapPath(dataFilePath);
  var userMessage = "Hello world, the time is " + DateTime.Now;
  var userErrMsg = "";
  var errMsg = "";

  if (IsPost)
  {
    try
    {
      // השורה הבאה תגרום לכישלון - מיכוון ששם הקובץ שגוי
      fileContents = File.ReadAllText(@"c:\batafile.txt");
    }

//שגיאת קובץ לא קיים
    catch (FileNotFoundException ex)
    {
      errMsg = ex.Message;
      // אנו יוצרים כעת הודעה נעימה יותר שתוצג עבור המשתמש
      userErrMsg = "A file could not be opened, please contact "
          + "your system administrator.";
    }

 //שגיאת תיקייה לא קיימת
    catch (DirectoryNotFoundException ex)
    {
      // אנו יוצרים כעת הודעה נעימה יותר שתוצג עבור המשתמש
      errMsg = ex.Message;
      userErrMsg = "A directory was not found, please contact "
          + "your system administrator.";
    }
  }
  else
  {
    File.WriteAllText(physicalPath, userMessage);
  }
}
<!DOCTYPE html
>
<
html lang
="en">
<
head>
  <meta charset="utf-8" />
  <title>Try-Catch Statements</title
>
</
head
>
<
body>
  <form method="POST" action="">
  <input type="Submit" name="Submit" value="Open File" />
  </form>
  <p>@fileContents</p>
  <p>@userErrMsg</p
>
</
body
>
</
html
>

תגיות: ,

ליאור זמיר

כיום אני ה- Webmaster של תוכנית החדשנות של HPE Software.לפני כן, הייתי מנהל תחום Webmaster ומרצה בכיר בג'ון-ברייס (במשך 9 שנים) בקורסים לפיתוח ותיכנות באמצעות Microsoft .NET, מולטימדיה, בניית אתרי אינטרנט ואינטראנט. פיתוח הדרכה ומתן ייעוץ טכנולוגי.

תגובות בפייסבוק