系列導航地址http://www.cnblogs.com/fzrain/p/3490137.htmlhtml
題外話:因爲這個技術點是新學的,並不屬於原系列,但藉助了原系列的項目背景,故命名外傳系列,之後也可能在這個系列中附加一些新的技術。git
在Web Api 2.0中,提出了一種新的配置路由方式——基於特性的路由(Attribute-based Routing),在咱們以前介紹的配置路由方式稱爲——基於公約的路由(Convention-based Routing),新的路由配置方式一樣應用在MVC5中,所以本文就來介紹一下基於特性的路由。github
在以前的一篇文章中,咱們處理了這麼一個業務——實現學生選課。咱們是經過在「WebApiConfig」定製了一條路由數據來實現的,這條路由實現了選課以及根據課程Id來查詢選擇選擇該課程的全部學生信息,感受設計還能夠。在實際應用中通常來講查詢用的是最多的,使用Attribute Routing來註冊路由會更靈活,控制起來也更方便,更符合Rest。本文以根據課程的名字來查詢全部選擇該課程的學生信息以及根據課程名字以及學生名字查詢某一學生的信息。web
顧名思義,新路由將使用一個特性來實現路由註冊,以下:api
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=true)] public sealed class RouteAttribute : Attribute, IHttpRouteInfoProvider { public RouteAttribute(); public RouteAttribute(string template); public string Name { get; set; } public int Order { get; set; } public string Template { get; private set; } }
這個類包含3個屬性:Name指路由的名字,Order是指路由的順序,Template就是咱們要去匹配URL的模板app
原理性的東西很少介紹的(我也沒多研究 呵呵),能把學到的技術運用到實際中才是王道,上來一大堆原理容易暈,之後須要深刻研究再看原理。ide
在「EnrollmentsController」中新增一個方法GetStudentsInfo:測試
[Route("api/enrollments/{courseName}/{studentName?}")] public IEnumerable<StudentBaseModel> GetStudentsInfo(string courseName, string studentName="") { IQueryable<Student> query; Course course= TheRepository.GetAllCourses().Where(c => c.Name == courseName).FirstOrDefault(); if (course==null ) { return null ; } query = TheRepository.GetEnrolledStudentsInCourse(course.Id).OrderBy(s => s.LastName); if (!string.IsNullOrWhiteSpace(studentName)) { query = query.Where(s => s.FirstName == studentName); } var totalCount = query.Count(); System.Web.HttpContext.Current.Response.Headers.Add("X-InlineCount", totalCount.ToString()); var results = query .ToList() .Select(s => TheModelFactory.Create(s)); return results; }
在咱們的Action上使用了RouteAttribute。分析一下這個URL模板("api/enrollments/{courseName}/{studentName?}"),{courseName}會匹配到Action的courseName參數上,對於Action的另外一個參數studentName是一個可選參數,也就是說請求中沒有給出值那麼就是默認的空字符串,有值得話就會被賦值,所以咱們在「{studentName}」後面加上? 標記爲可選的URI參數。spa
ok,就這麼簡單,測試一次:設計
結果:
呃,出錯了。。。
出錯了,不過無論怎麼說解決方案總歸是有的,首先看下錯誤緣由:是在LearningControllerSelector類的方法中出現了空引用,那麼咱們就不得不看下這個方法:
public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { var controllers = GetControllerMapping(); //Will ignore any controls in same name even if they are in different namepsace var routeData = request.GetRouteData(); var controllerName = routeData.Values["controller"].ToString(); HttpControllerDescriptor controllerDescriptor; if (controllers.TryGetValue(controllerName, out controllerDescriptor)) { var version = "2"; var versionedControllerName = string.Concat(controllerName, "V", version); HttpControllerDescriptor versionedControllerDescriptor; if (controllers.TryGetValue(versionedControllerName, out versionedControllerDescriptor)) { return versionedControllerDescriptor; } return controllerDescriptor; } return null; }
看了這段代碼咱們不難發現這個方法是咱們重寫了基類的方法,目的是爲了實現現版本控制(詳情可移步:http://www.cnblogs.com/fzrain/p/3558765.html),在咱們重寫的方法中咱們用到了RouteData中包含的Controller的名字,而這個名字是由基於公約的路由與URI匹配獲得的,所以咱們這裏確定是沒有的。由於咱們的項目混合了2鍾路由配置,而自定義的方法是針對基於公約的路由配置,所以對於Attribute Routing咱們直接使用默認的選擇方式:
在「var controllerName = routeData.Values["controller"].ToString(); 」代碼以前加一個判斷:
if (string.IsNullOrWhiteSpace(routeData.Route.RouteTemplate)) { return base.SelectController(request); }
再次請求就會獲得以下結果:
結果正確,解決方案感受還能夠再考慮考慮,你們有什麼好的建議能夠提。可是無論怎麼說,有一點是明確的:對於基於特性的路由規則,不須要包含Controller的名字,在本案列中感受上是尋找Acton上的路由模板來匹配請求的URI,而後肯定對應的Action。
基於特性路由(Attribute Routing)是一種新的定製路由規則方式,與傳統的配置方式相比更靈活,但同時比較分散,在web api中,2鍾路由配置方式能夠共存,因此本文只是介紹一種新的配置方式,作項目時也能夠多一種選擇。
本文參考相關連接:http://www.cnblogs.com/aehyok/p/3449851.html