1. 程式人生 > >MVC——WebApi(學習之路1)

MVC——WebApi(學習之路1)

一、MVC和WebApi路由機制比較

1、MVC裡面的路由

在MVC裡面,預設路由機制是通過url路徑去匹配對應的action方法,比如/Home/GetUser這個url,就表示匹配Home這個Controller下面的GetUser方法,這個很好理解,因為在MVC裡面定義了一個預設路由,在App_Start資料夾下面有一個RouteConfig.cs檔案

複製程式碼

    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 = "Department", action = "Index", id = UrlParameter.Optional }
            );
        }
    }

複製程式碼

url: "{controller}/{action}/{id}"這個定義了我們url的規則,{controller}/{action}定義了路由的必須引數,{id}是可選引數

二、WebApi路由基礎

1、預設路由

上面我們提到了,新建一個WebApi服務的時候,會自動在WebApiConfig.cs檔案裡面生成一個預設路由:

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

將MapHttpRoute()方法轉到定義可以,它有四個過載方法:

分別來看看各個引數的作用:

  • name:"DefaultApi"→表示此路由的名稱,這裡只需要保證路由名稱不重複就OK了。
  • routeTemplate: "api/{controller}/{id}"→表示路由的url規則,“api”是固定部分,主要用來標識當前請求的url是一個api服務的介面,區別MVC的路由,當然,這裡並不是一定要寫成“api”,如果你改成“apiserver”,那麼你請求的url裡面也需要寫成“apiserver”;“{controller}”是控制器的佔位符部分,在真實的url裡面,該部分對應的是具體的控制器的名稱,這個和MVC裡面一致;“{id}”是引數的佔位符部分,表示引數,一般這個引數都會在default裡面設定可選。有了這個路由模板約束請求的url,比如:我們請求的url寫成http://localhost:21528/Order,那麼肯定是找不到對應的路由的,因為“api”這個引數必選。如果請求的url匹配不到對應的路由,則會向客戶端返回一個404的狀態碼。
  • defaults: new { id = RouteParameter.Optional }→表示路由的預設值,比如上面的routeTemplate,{controller}和{id}部分都可以設定預設值,比如:defaults改成new { controller="Order", id = RouteParameter.Optional },那麼我們請求http://localhost:21528/api這個url仍然能訪問到GetAll()方法。
  • constraints→表示路由約束,一般是一個約束路由模板的正則表示式。比如:我們加入約束條件 constraints: new { id = @"\d+" } ,這就約束必須要匹配一到多個引數id,那麼,我們在OrderController裡面加入另一個方法

複製程式碼

    public class OrderController : ApiController
    {

        [HttpGet]
        public object GetAll()
        {
            return "Success";
        }

        [HttpGet]
        public object GetById(int id)
        {
            return "Success" + id ;
        }
    }

複製程式碼

我們通過http://localhost:21528/api/Order/2來訪問,得到結果:

我們再通過http://localhost:21528/api/Order/a來訪問,得到結果:

這個是很好理解的,id的值不匹配正則表示式。

而我們訪問http://localhost:21528/api/Order。結果:

竟然連GetAll()方法都找不到了。這是為什麼呢?原來就是這個約束在作怪,正則\d+表示匹配一個或多個數字,所以如果請求的url裡面沒有傳數字,則自動匹配不到。所以,如果需要匹配無參的方法,我們把約束改成這樣: constraints: new { id = @"\d*" } ,這個表示匹配0個或多個數字,再來試試

這樣就OK了。

上述說了那麼多都是約束id的,其實你也可以使用表示式去約束controller、action等等,但一般不常用,我們就不做過多講解。

回到頂部

2、自定義路由

上面介紹了這麼多,都是關於預設路由原理的介紹。除了預設路由,我們也可以自定義路由,我們將WebApiConfig.cs裡面改成這樣:

複製程式碼

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 路由
            config.MapHttpAttributeRoutes();

            //1.預設路由
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            //2.自定義路由一:匹配到action
            config.Routes.MapHttpRoute(
                name: "ActionApi",
                routeTemplate: "actionapi/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            //3.自定義路由二
            config.Routes.MapHttpRoute(
                name: "TestApi",
                routeTemplate: "testapi/{controller}/{ordertype}/{id}",
                defaults: new { ordertype="aa", id = RouteParameter.Optional }
            );
        }
    }

複製程式碼

除了預設路由,我們再加入另外兩個自定義路由規則

2.1、自定義路由一:匹配到action

第一個自定義路由很好理解,和MVC裡面的路由機制保持一致,只不過為了區別預設路由,我們將路由模板的字首改成了“actionapi”。我們通過這個自定義的路由也能找到匹配的方法。

比如我們訪問http://localhost:21528/actionapi/Order/GetAll,得到結果:

通過action的名稱來匹配很好理解,上面的GetAll()是方法名,webApi會預設它就是action的名稱,如果你想要方法名和action的名稱不一致,你也可以自定義action的名稱,這個可以通過特性ActionName來實現,如下:

        [ActionName("TestActionName")]
        [HttpGet]
        public object GetById(int id)
        {
            return "Success" + id ;
        }

測試結果:

之前博主演示引數和返回值的時候都是使用的匹配到action的路由。這種用法和MVC裡面保持一致,比較好理解,但是WebApi裡面並不提倡。

2.2、自定義路由二

第二個自定義路由第一眼看上去是不太好理解的,沒關係,我們先來按照它的路由模板規則使用試試。

通過http://localhost:21528/testapi/Order/aa/匹配到GetAll()方法

通過http://localhost:21528/testapi/Order/aa/2匹配到的是GetById()方法

通過http://localhost:21528/testapi/Order/bb/2匹配到的也是GetById()方法。

什麼意思呢?也就是說,只要{ordertype}按照路由規則去配置,都能找到對應的方法。這裡的{ordertype}有什麼用呢?這個要留在下面介紹特性路由的時候來解釋。

//////////////////

經過上面的學習總結了幾個自己的測試用例:

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

namespace MVCWebApi1 {     /// <summary>     /// 配置WebApi     /// </summary>     public static class WebApiConfig     {

        /// <summary>         /// 專案啟動後路由配置將呼叫方法         /// </summary>         /// <param name="config">傳入路由配置</param>         public static void Register(HttpConfiguration config)         {             //// 啟用Web API特性路由             //config.MapHttpAttributeRoutes();

            //1.預設路由             config.Routes.MapHttpRoute(                 name: "DefaultApi",//本路由的名稱

               routeTemplate: "api/{controller}/{id}",//路由的格式:對映地址+api(可以換名字)+/+controller(控制檯的方法)+/+id(傳入的值)                               // routeTemplate: "login/{controller}/{id}", //測試

               defaults: new { id = RouteParameter.Optional }                 //defaults: new { id = @"\d+"} //必須帶參才能訪問介面: \d+表示匹配一個或多個數字 、id = @"\d*"表示匹配0個或多個數字(測試失敗)                // defaults: new { controller = "values", id = RouteParameter.Optional } //設定預設值:預設介面(控制器類ValuesController)為values,id預設值為可選(可有可無)。             );

            // 取消註釋下面的程式碼行可對具有 IQueryable 或 IQueryable<T> 返回型別的操作啟用查詢支援。             // 若要避免處理意外查詢或惡意查詢,請使用 QueryableAttribute 上的驗證設定來驗證傳入查詢。             // 有關詳細資訊,請訪問 http://go.microsoft.com/fwlink/?LinkId=279712。             //config.EnableQuerySupport();

            // 若要在應用程式中禁用跟蹤,請註釋掉或刪除以下程式碼行             // 有關詳細資訊,請參閱: http://www.asp.net/web-api

            //2.自定義路由一:匹配到action             config.Routes.MapHttpRoute(                 name: "login",                 routeTemplate: "login/{controller}/{action}/{id}",                 defaults: new { id = RouteParameter.Optional}                 );

            //3.自定義路由二             config.Routes.MapHttpRoute(                 name: "TestApi",                 routeTemplate: "api/{controller}/{ordertype}/{id}",                 defaults: new { ordertype = "aa", id = RouteParameter.Optional }             );

            config.EnableSystemDiagnosticsTracing();         }     } }

/*  通過上文路由的過程,我們知道,一個請求過來之後,路由主要需要經歷三個階段

根據請求的url匹配路由模板 找到控制器 找到action  */

最後因為

  //[Route("Values/SaveData")] //需要引用包:Microsoft.AspNet.WebApi.Core         //[HttpPost]         //public HttpResponseMessage SavaData(object order)         //{         //    return Request.CreateResponse();         //}

這部分引用了一個包然後整個專案就崩潰了