ASP.NET MVC 5 Web編程2 -- URL映射(路由原理)


本章將講述ASP.NET MVC5 的路由原理,即URL映射機制。

簡單點就是解釋:為什么MVC在瀏覽器輸入地址就能訪問到類(或類中的方法)?這是怎么做到的?我自己可以通過.NET寫出一個自己的MVC框架嗎?

答案是:可以。

模擬URL映射

先來看一個Demo,在傳統的.NET WebForms項目中,實現URL的攔截。

打開VS2013,新建一個“ASP.NET Web窗體應用程序”項目,並取名為Demo4URLRouting。

為了方便測試,注釋掉Default.aspx頁面的內容和模板引用。這樣做以后,看起來是這樣

然后新建一個ControllerFactory類,實現IHttpHandler接口。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 
 6 namespace Demo4URLRouting
 7 {
 8     /// <summary>
 9     /// 自己寫的ControllerFactory,試圖扮演MVC5中的RouteConfig(路由配置)角色。
10     /// </summary>
11     public class ControllerFactory : IHttpHandler
12     {
13         ControllerFactory()
14         { 
15         }
16 
17         public bool IsReusable
18         {
19             get;
20             set;
21         }
22 
23         public void ProcessRequest(HttpContext context)
24         {
25             context.Response.Write(string.Format("ControllerFactory來攔截請求-> URL為: {0}",context.Request.RawUrl));
26         }
27     }
28 }
View Code

下一步,打開Web.config配置文件,在system.webServer節點下添加一項handlers配置

代碼如下:

<!--for url routing test Start-->
    <handlers>
      <add name="ControllerFactory" verb="*" path="*Account/*" type="Demo4URLRouting.ControllerFactory,Demo4URLRouting" preCondition="integratedMode"/>
    </handlers>
    <!--for url routing test End-->
View Code

此配置的意圖是:攔截站點URL中包含Account關鍵字的全部URL地址。

按F5運行項目,在地址欄站點后,輸入account,發現已成功被ControllerFactory類攔截。

繼續,輸入/account/login。發現地址未被攔截。而是跳轉到了默認項目的登陸頁面。

怎么回事呢?

原來,是項目下的Global.asax文件中的內容引起,注釋掉RouteConfig注冊的路由。

重新輸入/account/login,發現已成功被ControllerFactory類攔截。

現在我們修改下ControllFactory類中ProcessRequest方法的代碼,實現URL和類及類中方法的映射。(注意,代碼做了非常簡單的處理,我們假定忽略大小寫因素,路由格式也和傳統MVC類似)

 1 public void ProcessRequest(HttpContext context)
 2         {
 3             context.Response.Write(string.Format("ControllerFactory來攔截請求-> URL為: {0}",context.Request.RawUrl));
 4             context.Response.Write("<br/>");
 5 
 6             /**
 7              * 將攔截的URL地址分發給對應的Controller
 8              **/
 9             //簡單處理,截取URL中第一個/和/之間的字符串做為要查找的Controller對象
10             string url = context.Request.RawUrl;
11             string actionURL = url.IndexOf('?') > 0 ? url.Substring(0, url.IndexOf('?')) : url.Substring(0);
12             string[] strArray = actionURL.Split('/');
13             //得到類名稱
14             string targetClassName = (strArray[1] + "Controller");
15             string methodName = string.Empty;
16             if (strArray.Length > 2 && !string.IsNullOrEmpty(strArray[2]))
17                 methodName = strArray[2];//以'/'做分割,類名稱后為方法名稱
18             /**
19              * 從URL獲取類名稱之后,利用反射實現方法的調用。
20              **/
21             //獲取Controller實例
22             object instance = Activator.CreateInstance(Type.GetType(string.Format("Demo4URLRouting.Controllers.{0}", targetClassName)));
23             if (instance != null)
24             {
25                 object outputObj = null;//方法輸出內容
26                 if (string.IsNullOrEmpty(methodName) || instance.GetType().GetMethod(methodName) == null)
27                     methodName = "Index";//如果url沒有輸入方法或方法不存在,默認調用Index方法
28                 try
29                 {
30                     //調用實例方法
31                     outputObj = instance.GetType().GetMethod(methodName).Invoke(instance, null);
32                     context.Response.Write(outputObj);
33                 }
34                 catch(MissingMethodException mme)
35                 {
36                     context.Response.Write(string.Format("<font color='red'>Error! Method not Found!</font>  {0}",mme.Message));
37                 }
38             }
39         }
View Code

在代碼中,進行了簡單的url分析,獲取類名和方法名,再通過反射機制,實現調用。

然后,為了配合測試,我們在解決方案中新建一個Controllers文件夾,在該文件夾下新建一個類AccountController,代碼如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Demo4URLRouting.Controllers
{
    public class AccountController
    {
        public string Index()
        {
            return "this is the AccountController,<b>Index</b> method.";
        }

        public string HelloWorld()
        {
            return "this is <font color='red'>HelloWorld method</font> which is in the Class named AccountController.";
        }

    }
}
View Code

AccountController類中定義了兩個方法,Index()和HelloWorld()。然后我們通過瀏覽器進行訪問

可以看到,通過在瀏覽器地址中,輸入/Account,實現對AccountController類中Index方法的訪問;輸入/Account/HelloWorld實現對AccountController類中的HelloWorld方法的訪問。

到此,我們初步實現了在WebForms環境下,URL到類的映射。此過程的核心是handlers的配置和利用反射原理調用類中的方法。Demo的不足是沒有去消除大小寫問題,沒有更靈活的路由配置等。

那么問題來了,MVC中這一整套URL映射的機制,是如何實現的呢?

MVC5 URL映射機制

實際上,在寫本篇文章之前,我翻看了大量網上有關MVC的資料,發現大多數對MVC映射機制(也叫MVC路由機制)的描述都非常籠統。

類似不懂裝懂,或者讓你去理解Model-View-Controller的三層,什么業務分離,或者說了半天說一堆廢話。。。我是深惡痛絕的。如果僅僅是解釋微軟MSDN上能查到的東西?那你的解釋意義在哪里?不說了,泡沫信息太多了。

在了解MVC URL映射機制這一套原理之前,你首先要了解ASP.NET Routing。 ASP.NET Routing是.NET的一套獨立組件。總的來說,它可以做兩件事情:

1. 將URL請求地址的片段轉交到handler處理;

2. 構造(創建)URL地址。

Routing目前的信息實在太少,感興趣的可以在MSDN上做初步了解。總的來說,Routing做了我們前面模擬做的所有事情,而且毋庸置疑,做的更好更強大。

在MVC中,從URL到Controller,簡要過程大概是這樣:

URL -->  RouteData對象 --> MvcHandler對象 --> IControllerFactory接口 --> Controller 

這個過程很復雜,要詳細闡述其過程,估計要三篇文章以上的篇幅。這里就不再闡述。

MVC框架中,RouteConfig類中這段代碼已經做了URL到Controller映射的所有工作。你所需要做的,只是匹配Controller了。

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
View Code

總結

本篇文章重點講述了ASP.NET MVC中的URL映射機制。先是通過在WebForms中模擬URL映射,讓初學者有一個直觀的認識。然后簡要的介紹了MVC中URL映射的機制。由於篇幅所限,在介紹URL映射機制時,只做了簡要的闡述。因為知識量很大,而且建議讀者要有ASP.NET Routing組件的基礎。關於Routing組件,以后有空的話,我再單獨寫文章來講。

在下一篇文章中,我將講述Controller的實際應用及擴展,項目中Controller扮演的角色。敬請期待。

本文原始地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM