יצירת מנגנון shortcut url באמצעות מנגנון ה - routing של asp.net
יחד עם ה - MVC הגיע dll מאוד נחמד ששמו System.Web.Routing, הוא משמש מנגנון מאוד מרכזי ב - MVC כדי להפנות לדף המתאים לפי הבקשה .
היות שהוא כל כך מוצלח ניתן להשתמש בו גם ב - asp.net לצרכים אחרים.
(חשוב לציין שיכול שמן הסתם רוב הלינקים בפוסט לא יעבדו - אלא הם הדגמה למה אפשר לעשות)
אז כמובן שמן הסתם תהיה מערכת ניהול ויש לנו בסיס נתונים או קובץ XML שבו נשמרים כל קיצורי הדרך ולהיכן זה צריך להגיע - אבל מה שחשוב זה מנגנון ה - routing ואיך זה עובד.
(בשבוע הקרוב אני אעלה בעז"ה ל - CODE PLEX פרויקט של ה - routing יחד עם מנגנון הניהול שלו - כשזה יעלה אני אפרסם את הלינק)
לבנתיים נראה איך ה - routing עובד
אז ככה - דבר ראשון יש להוסיף לפרויקט שלכם שני reference
1. System.Web.Abstractions
2. System.Web.Routing
לאחר מכן ב - Global.asax בארוע Application_Start צריך לרשום מי יהיה אחראי לטפל בבקשות שיגיעו
protected void Application_Start(object sender, EventArgs e)
{ List<string> titleData = Dal.GetAllTitles();
WebFormRouteHandler webFormRouteHandler = new WebFormRouteHandler();
RouteTable.Routes.Add("4D81C761-A6ED-450f-8618-618A17EFBA99", new Route("4D81C761-A6ED-450f-8618-618A17EFBA99", webFormRouteHandler));
for (int i = 0; i < titleData.Count; i++)
{ RouteTable.Routes.Add(titleData[i], new Route(titleData[i], webFormRouteHandler));
}
}
ואני אסביר -
בשלב ראשון אני מקבל מבסיס הנתונים את כל קיצורי הדרך - לדוגמא syllabus/c2.
אני יוצר מופע של WebFormRouteHandler (עוד מעט נראה אותו).
נתעלם כרגע מהשורה הבאה ונדלג לללואה. (נתייחס לזה בהמשך)
אנחנו עושים מעבר על כל קיצורי הדרך - ומוסיפים ל - RouteTable (שזה מגיע מ - System.Web.Routing) את קיצור הדרך ומי אמור לטפל בבקשה - שזה האובייקט שיצרנו.
בפועל מה שהקוד עושה זה, להגדיר כשיגיע request שמכיל ב - url את קיצור הדרך (בדוגמה שלנו - syllabus/c2) מי שיטפל בבקשה זה לא המנגנון הרגיל של asp.net אלא המחלקה שיצרנו - כלומר המופע של WebFormRouteHandler).
כעת נראה את הקוד של המחלקה WebFormRouteHandler
public class WebFormRouteHandler : IRouteHandler
{ #region IRouteHandler Members
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{ return new RoutingHandler();
}
#endregion
}
כמו שאנחנו רואים - אין בו הרבה קוד, בסך הכל מימוש של interface בשם IRouteHandler (שזה מה שה - RouteTable מקבל) ובמימוש שלו צריך להחזיר מישהו שמממש את IHttpHandler - כשלמעשה אנחנו מחזירים מופע של RoutingHandler)
הנה המחלקה
public class RoutingHandler : UrlRoutingHandler
{ protected override void VerifyAndProcessRequest(IHttpHandler httpHandler,
HttpContextBase httpContext)
{ string tempTitle = httpContext.Request.Url.AbsolutePath;
if (tempTitle.Contains("4D81C761-A6ED-450f-8618-618A17EFBA99")) { Global.Register();
return;
}
tempTitle = tempTitle.Remove(0, 1);
tempTitle = tempTitle.Substring(tempTitle.IndexOf('/') + 1);
string titleData = Dal.GetUrl(tempTitle);
httpContext.Response.Redirect(titleData);
}
}
המחלקה יורשת מ - UrlRoutingHandler שמממשת את IHttpHandler - אנחנו נעשה override ל - VerifyAndProcessRequest שהיא המתודה שצריכה להחליט לאיפה לנווט ומה להחזיר כתשובה לבקשה.
בהתחלה אני לוקח את ה - absolutePath.
נדלג כרגע על הבדיקה עם ה - GUID (נתייחס בהמשך)
המשתנה tempTitle יהיה שווה ל - url/syllabus/c2/ (זה ה - absolutePath)
אני מעיף את תו ה - / הראשון. ואז את כל השאר עד תו ה - / השני - כלומר אני אשאר עם syllabus/c2 (שזה כזכור קיצור הדרך)
אני מתשאל את בסיס הנתונים לאיפה צריך לנווט בהתבסס על קיצור הדרך - ואני מנווט לאותו מיקום.
כמעט סיימנו - נשארו דברים.
הראשון איך אומרים ל - IIS שאנחנו מטפלים בבקשות - כלומר, כשמגיעה בקשה לשרת שנראית:
http://www.sela.co.il/url/syllabus/c2 אזי IIS אמור לחפש תיקייה שנקראת c2 תחת תיקייה שנקראת syllabus בתוך ה - virtual directory שנקרא url - וכמובן הוא לא ימצא, ולכן אנחנו צריכים להגדיר ל - IIS שלא הוא מטפל בבקשות אלא אנחנו.
כדי לעשות זאת זה תלוי האם מדובר ב - IIS 7 או בגרסה קודמת, במידה שמדובר ב - IIS 7 זה הגדרה פשוטה בקובץ הקונפיג, בחלק התחתון של ה - web.config יש מקטע שנקרא system.webServer בתוכו יש מקטע שנקרא modules, צריך להוסיף זם את הקוד הבא:
<add name="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule,
System.Web.Routing, Version=3.5.0.0,
Culture=neutral,
PublicKeyToken=31BF3856AD364E35" />
בנוסף במקטע של handlers צריך להוסיף את הקוד הבא:
<add name="UrlRoutingHandler"
preCondition="integratedMode"
verb="*"
path="UrlRouting.axd"
type="Routing.RoutingHandler, Routing"/>
כשצריך לשים לב לחלק של ה - type שזה צריך להיות האובייקט שלנו והשם של ה - namespace שלנו.
וזה יעבוד.
במידה ומדובר על גרסאות קודמות של IIS (הגרסה הכי מוקדמת שזה יכול לעבוד זה על server 2003 - צריך לקנפג את זה גם בקונפיג וגם ב - IIS.
בקונפיג תחת המקטע של httpHandlers צריך להוסיף
<add verb="*" path="*" type="Routing.RoutingHandler" />
ב - IIS (אין לי כרגע windows server 2003 אז הייתי צריך לחפש את התמונות בגוגל - ולכן תתעלמו מהעיגולים האדומים או מההגדרות שיש בתמונות ותתיחסו רק למה שאני כותב).
שלב ראשון אחרי הגדרת ה - virtual directory נלחץ על configuration
(העיגול מסביב ל - Script and Execute הגיע מהתמונה המקורית - אין לזה קשר על מה שאנחנו מדברים כרגע)
נקבל את החלון הבא:
נלחץ על Insert כדי להגדיר ל - IIS מי מטפל בבקשות שנכנסות
יש להכניס ב - execute את הנתיב של asp.net כמדומני שזה C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll אבל אני לא בטוח - אפשר תמיד לבדוק מה הנתיב של הסיומת של ה - aspx בחלון ה - Configuration.
לא לשכוח לוודא ש - Verify taht file exists לא מסומן.
הדבר האחרון שאני צריך להסביר - מה העניין עם ה - GUID ב - Applicatuin_Start וב - VerifyAndProcessRequest.
העניין הוא כזה - היות שאנחנו רושמים את כל קיצורי הדרך בזמן Application_Start, בזמן שנוסיף קיצורי דרך בבסיס הנתונים מנגנון ה - Routing לא יודע מזה ולכן זה לא ירשם ב - RouteTable עד שהאפליקצייה לא תמות (או שנעשה iisreset) ולכן הפיתרון היה לרשום ב - RouteTable מספר מיוחד שבמידה ומגיעים איתו זה ירענן את ה - RouteTable,
למעשה הקוד
RouteTable.Routes.Add("4D81C761-A6ED-450f-8618-618A17EFBA99", new Route("4D81C761-A6ED-450f-8618-618A17EFBA99", webFormRouteHandler));
string tempTitle = httpContext.Request.Url.AbsolutePath;
if (tempTitle.Contains("4D81C761-A6ED-450f-8618-618A17EFBA99")){ Global.Register();
return;
}
הקוד יושב במתודת VerifyAndProcessRequest הוא יבדוק האם ההפנייה היא עם ה - GUID - במידה וכן נפעיל מתודה סטטית ב - Global.asax שמעדכנת את ה - routeTable מבסיס הנתונים.