DCSIMG
שילוב URL Rewriting ע"י System.Web.Routing - שחר.נט

שחר.נט

בלוגים שאני קורא

ספרים מומלצים

שילוב URL Rewriting ע"י System.Web.Routing

URL Rewriting המבוסס על System.Web.Routing

מבוא

System.Web.Routing הוא אחד מה assemblies החדשים שהתווספו כחלק מ Visual Studio 2008 & .NET 3.5 Service Pack 1.
מדובר במנגנון המבוסס על זה שקיים בגרסאות ה preview של ASP.NET MVC, שהופרד ממעטפת הMVC, כך שיוכל לשמש באופן עצמאי גם באפליקציות Web Forms.
בנוסף, מנגנון הניתוב שפועל ב Dynamic Data Applications שהתווספו גם הם כחלק מחבילת שירות זאת מבוסס על  System.Web.Routing.

בפוסט זה נלמד כיצד לבנות, צעד אחר צעד, מנגנון URL Rewriting המובסס על System.Web.Routing.

המטרה

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

למה צריך URL Rewriting?

כאשר בונים כיום אפליקציות WEB, מקובל להתייחס לנושא שבעבר לא זכה להתייחסות רבה - SEO (ר"ת Search Engine Optimizing), ובשפת הקודש - מיטוב (שיפור) למען מנועי חיפוש. בעבר, כתובות אתרים רבות היו מכילות שורות פרמטרים שהועברו ב QueryString שהפכו את השימוש בכתובת לפחות ידידותי למנועי החיפוש.למשל, הכתובת הזאת:

http://www.MyOnlineShop.com/product.asp?action=buy&productId=1010&referrer=5060

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

http://www.MyOnlineShop.com/Product/ProductName/Buy - תהיה הרבה יותר ידידותית.

עד היום, כדי לעשות זאת, היה לא פעם צריך לעבוד קשה. באמצעות System.Web.Routing, העבודה הופכת לקלה הרבה יותר.

התיאוריה

כשאנחנו מדברים על בניית מנגנון ניתוב (URL Rewriting) המבוסס על System.Web.Routing, אנחנו מדברים על HttpModule שפועל עבורנו מאחורי הקלעים.
למעשה, System.Web.Routing מכיל מנגנון שיודע "לתפוס" את הפניות ולבצע ברמת השרת את הפעולות שאנחנו מגדירים.
כלומר, אם אנחנו רוצים, ניתן לעשות כל מיני פעולות נוספות, חוץ מההפנייה. במאמר זה, נתמקד בעיקר בהפניות פשוטות.

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

  1. להודיע לשרת שאנחנו עובדים עם המנגנונים של System.Web.Routing
  2. לרשום את הניתובים (מי מפנה למי)
  3. לממש את מנגנון הניתוב בצורה שיתאים לנו.

המעשה

1. הוספת ה HttpModule המתאים ב web.config

לפני הכל, אנחנו חייבים להגדיר ב web.config, במקטע של HttpModules שאנחנו מעוניינים לעבוד עם הראוטינג.
<add name="urlRouting" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing" />

2. הגדרת מסד הנתונים

מסד הנתונים שלי מכיל טבלה אחת בלבד, שמכילה 3 שדות: ID, מקור ולאן להפנות. את העבודה מול מסד הנתונים אני עושה באמצעות LINQ to SQL.

3. קביעת המיפויים

את קביעת המיפויים עצמה, אנחנו מבצעים בקובץ global.asax, ב event של Application_Start. קוד קביעת המיפויים נראה כך :

   15 protected void Application_Start(object sender, EventArgs e)

   16         {

   17             using (var db = new RoutingDataContext())

   18             {

   19                 foreach (var item in db.Routes)

   20                 {

   21                     RouteTable.Routes.Add(item.ID.ToString(), new System.Web.Routing.Route

   22                         (item.OriginalUrl.Trim(), new SampleRoutingHandler(item.RouteTo.Trim())));

   23                 }

   24             }

   25             RouteTable.Routes.RouteExistingFiles = true;

   26         }

למעשה, באמצעות LINQ to SQL, הקוד עובר על כל הערכים בטבלה Routes, ומכניס אותם ל RouteTable. הטבלה Routes נראית כך:

image

השדה OriginalUrl מכיל את מבנה הכתובת כפי שאני מצפה שהמשתמש יקיש אותו, כאשר שמות המוקפים בסוגריים מסולסלים, משמע שמות של פרמטרים. כלומר, אני מצפה שהמשתמש יגיע לכתובת Account/4 או כל מספר אחר, כאשר את ה-4 אני רוצה לקבל בתור פרמטר שה value שלו 4 וה key הוא id.
אני מעוניין שהדף שייקח את האחריות על המידע במקרה הזה, הוא MyPage.aspx.

הלוגיקה

System.Web.Routing, לא מספק מנגנון הפנייה מלא, אולם הוא מספק את כל מה שנדרש תשתיתית לבניית מנגנון URL Rewriting שיתאים לצרכינו, כפי שתיארנו אותם בהתחלה.
כדי באמת לבנות את פעולת ההפנייה עצמה, אנחנו צריכים ליצור class שיורש מ System.Web.Routing.IRouteHandler. לאינטרפייס הזה, יש רק מתודה אחת שאנחנו צריכים לממש, GetHttpHandler שמקבלת אובייקט System.Web.Routing.RequestContext ומחזירה IHttpHandler.

RequestContext, מאפשר לנו גישה לנתונים שהועברו לדף המקורי, כלומר, ל HttpContext שלו, ובנוסף מאפשר לנו לגשת ל RouteData, נתוני ההפנייה.

System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath

המתודה הסטטית הזאת, היא עיקר הלוגיקה שלנו.למעשה, היא מקבלת שני פרמטרים: string שמציין את הנתיב הוירטואלי של הרכיב WEB (במקרה שלנו, דף) שלו נרצה לעשות build ופרמטר שמציין את ה Type של אותו רכיב WEB, במקרה שלנו, ה type של Page.

הקוד של המחלקה שיורשת מ IRouteHandler

למעשה, ברמה הבסיסית, ככה צריך להיראות ה Class שלנו שמכיל את לוגיקת ה Routing (לחצו להגדלה):

   11 public class SampleRoutingHandler : IRouteHandler

   12     {

   13         private string WhereToRoute;

   14 

   15         public SampleRoutingHandler(string dest)

   16         {

   17             WhereToRoute = dest;

   18         }

   19 

   20         #region IRouteHandler Members

   21 

   22         public IHttpHandler GetHttpHandler(RequestContext requestContext)

   23         {

   24 

   25             return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath

   26                 (WhereToRoute, typeof(Page));

   27 

   28         }

   29 

   30         #endregion

   31     }

 

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

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

 

   11 public class SampleRoutingHandler : IRouteHandler

   12     {

   13         private string WhereToRoute;

   14 

   15         public SampleRoutingHandler(string dest)

   16         {

   17             WhereToRoute = dest;

   18         }

   19 

   20         #region IRouteHandler Members

   21 

   22         public IHttpHandler GetHttpHandler(RequestContext requestContext)

   23         {

   24             foreach (var item in requestContext.RouteData.Values)

   25             {

   26                 requestContext.HttpContext.Items.Add(item.Key, item.Value);

   27 

   28             }

   29             return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath

   30                 (WhereToRoute, typeof(Page));

   31 

   32         }

   33 

   34         #endregion

   35     }

 

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

השלב האחרון, זה לכתוב דף שישתמש במידע. נכתוב דף בשם Search.aspx, שאחראי על החיפוש, שיעבוד עם אותם הפרמטרים:

image

כאשר נריץ את הדף הזה עכשיו, נראה את הפלט הבא:

image image (גם בעברית)

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

סיכום

במאמר הזה ראינו איך ניתן בשלבים פשוטים לבנות מנגנון ניתוב כתובות שיאפשר למשתמשים שלנו (ובעיקר למנועי החיפוש) לעבוד מול כתובות ידידותיות.
ראינו איך ניתן לבסס את המנגנון הזה על מסד הנתונים, ואיך לבנות class שיורש מ System.Web.Routing.IRouteHandler כדי לממש לוגיקה לפעולת הניתוב.

אתם יכולים להוריד את Visual Studio 2008 & .NET 3.5 Service Pack 1 בגרסאת beta ולהתנסות.

בהצלחה!

תוכן התגובה

Adlai Maschiach כתב/ה:

יצא טוב , אהבתי

# May 13, 2008 4:17 PM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 8 and 6 and type the answer here:


Enter the numbers above: