Asp.Net MVC 路由
Asp.Net MVC 路由
使用URL請求應用程序時,該請求最終是通過Handler來完成,Asp.Net MVC 是通過一個自定義的
HttpHandler
--MVCHandler
來實現對Controller的激活和Action執行。但是在這之前對Controller和Action的解析是通過Asp.Net的URL路由系統來完成,整個路由系統是通過一個自定義的HttpModule
--UrlRoutingModule
來是實現的。
即: 路由是對URL到Controller和Action的映射及URL的輸出。
路由註冊與配置
Global.asax
包含了Asp.Net應用程序生命周期的handler事件。實現HttpApplication
Global.asax
文件中MVCApplication
類中實現Application_Start()
方法會在應用程序啟動時執行,且只執行一次。所以在該方法中註冊路由。
配置路由
在App_Start
文件下,新建RouteConfig.cs
文件裏配置路由信息。通過靜態方法RouteCollection.MapRoute()
配置路由信息。
如:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略該模式的URL routes.MapRoute( name: "Default",//路由名稱 url: "{controller}/{action}/{id}",//路由模板 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }//路由默認值,參數id可以為空 ); } }
name:為該路由名稱
url:為路由模板,
{}
是占位符。defaults:為路由默認值
註冊路由
當MVC應用程序第一次啟動時,會調用Global.asax
文件中MVCApplication
類的Application_Start()
方法。調用RouteConfig
類的靜態方法RegisterRoutes(RouteTable.Routes)
將RouteTable註冊到應用程序。
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes);//路由註冊到應用程序 BundleConfig.RegisterBundles(BundleTable.Bundles); } }
URL匹配
在配置路由裏創建了一個路由名為Default
的路由。該Default
路由由controller
,action
,id
三部分組成,其中id
為可選參數。
該路由可以匹配如下url:
- xxx.com/home/index/1
- xxx.com/home/index
- xxx.com/home
- xxx.com/
這些URL都會映射到如下Action:
public class HomeController :Controller
{
public ActionResult Index()
{
return View();
}
}
或
//在路由中id參數是可為空的,所以對於值類型的參數必須是可空的值類型。
public class HomeController :Controller
{
public ActionResult Index(int? id)
{
return View();
}
}
並且該Action
的參數名稱需要和Route
中的參數(id)一致。即也是id。才可以匹配xxx.com/home/index/1
否則只能通過url傳參匹配xxx.com/home/index?myparam=1
如:如果定義的Action如下
public class HomeController :Controller
{
public ActionResult Index(string str)
{
return View();
}
}
輸入xxx.com/home/index/1
時,會認為參數為空,即str
並沒有被賦值,但是依然會調用index
方法,只不過是認為str
為空。但是當你通過url傳參請求時xxx.com/home/index?str=hello
,是可以匹配到這個Action
,也可以給str
賦值。
在同一個Controller下是不允許有Action重載的
如:
public class HomeController :Controller
{
public ActionResult Index(int? id)
{
return View();
}
public ActionResult Index()
{
return View();
}
}
在請求時提示錯誤:在對控制器類型“HomeController”的操作Index的請求方法不明確。
路由順序和優先級
路由引擎在定位路由時,會遍歷路由集合中的所有路由。只要發現了一個匹配的路由,會立即停止搜索。所以定義路由一定要註意路由的先後循序。一般是越是精確的放在前面。
如:有一個如下的路由配置
routes.MapRoute{
name: "one",
url:"{site}",
defaults:new{controller="MyControllerOne",action="Index"}
}
routes.MapRoute{
name:"two",
url:"Admin",
defaults:new {controller="Admin",action="Index"}
}
第一個路由有一個{site}占位符。默認的控制器為MyControllerOne
。第二個路由是一個常量Admin,
默認的控制器為Admin
。這兩個都是正確的路由配置。但是當我們輸入urlxxx.com/admin
時,我們預想的是請求AdminController
下的Index
操作方法。但是根據上面的路由映射,該url會匹配第一個路由,然後就停止了路由查找。此時觸發的Controller
為MyControllerOne
。
路由約束
之前的路由配置,都沒有url的參數的類型信息。如果我們的Action是一個Int類型,但是url中的參數是個字符串,這樣就會導致錯誤。所以如果有url的類型約束可以規避這個錯誤的發生。
在Asp.Net MVC中我們可以通過正則表達式來約束路由。
如:
routes.MapRoute{
"Default",
"{controller}/{action}/{id}",
new{controller="Home",action="Index",id=UrlParameter.Optional},
new{id="\d+"}//該id為整數
}
除了使用正則表達式來約束路由,我們還可以通過繼承IRouteConstraint接口自定義約束規則
如:
public class MyRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
//獲取id的值
var id = values[parameterName];
//id驗證方法
return true;
}
}
更新路由配置
routes.MapRoute{
"Default",
"{controller}/{action}/{id}",
new{controller="Home",action="Index",id=UrlParameter.Optional},
new{id=new MyRouteConstraint()}
}
That‘s it
如有不對,請多多指教。
Asp.Net MVC 路由