asp.net mvc 增加WebApi

新建項目的時候可以直接勾選

勾選,“確定”後你會發現,項目多了這些文件

一、App_Start文件夾多了WebApiConfig.cs文件

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

namespace HaoSiJiaWeb
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服務

            // Web API 路由
            config.MapHttpAttributeRoutes();

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

 

 config.MapHttpAttributeRoutes();

 

這行代碼的意思是開啓的特性路由

之前寫MVC的時候介紹過特性路由,感興趣的可以點擊下面鏈接進行查看

asp.net mvc 控制器和視圖的花式玩法

https://blog.csdn.net/cplvfx/article/details/102455928

 

二、Global.asax多了一行代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace HaoSiJiaWeb
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}
  GlobalConfiguration.Configure(WebApiConfig.Register);

 

如果你想在你的現有MVC項目增加WebApi可以根據這個格式(步驟)加進去就行了

 

增加WebApi控制器

第一步:新建文件夾

在網站根目錄新建文件夾“API”

第二步:增加控制器文件

在“API”文件夾右鍵》添加》Web API 控制器類

輸入名稱“TestController”

會生成下面代碼

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

namespace HaoSiJiaWeb.Api
{
    public class TestController : ApiController
    {
        // GET api/<controller>
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/<controller>/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/<controller>
        public void Post([FromBody]string value)
        {
        }

        // PUT api/<controller>/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/<controller>/5
        public void Delete(int id)
        {
        }
    }
}

訪問

訪問地址:http://localhost:58088/api/Test

目前訪問的是第一個action的Get方法

注意:

直接輸入地址訪問的http請求都屬於Get請求。

我們在提交表單的時候會有許多提交請求的方式,API會先判斷你請求的方式,再根據你的請求方式去找到控制器裏對應的action方法

在Web API裏還有個特性,就是action方法開頭如果是Get,他就會判定這個action是用來處理get請求的,

如果POST開頭,他就會判定這個action是用來處理post請求的,

像put和delete也都類似

 

代碼升級

升級TestController 控制器文件

在文件裏增加下面方法

    public class TestController : ApiController
    {
      
        public string TestString()
        {
          return "TestString()";
        } 
    }

我這裏把所有生成的方法都刪了,只留我自己寫的 

升級路由文件WebApiConfig

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服務

            // Web API 路由
            config.MapHttpAttributeRoutes();

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

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

我這裏在下面增加了一條新的路由狀態

訪問

url:http://localhost:58088/api/Test/TestString/

理論上,我們這樣訪問是沒有錯的,可惜,只是理論上

運行報錯

<Error>

<Message>請求的資源不支持 http 方法“GET”。</Message>

</Error>

根據,上面我們講的

在Web API裏還有個特性,就是action方法開頭如果是Get,他就會判定這個action是用來處理get請求的,

如果POST開頭,他就會判定這個action是用來處理post請求的,

像put和delete也都類似

我們把方法改成這樣的

 public string GetTestString()
{
          return "GetTestString()";
} 

在名字前面增加Get

訪問url:http://localhost:58088/api/Test/TestString/

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">GetTestString()</string>

已經訪問成功了

那麼,有沒有另一種方法呢?

答案是“有”,在方法上面增加特性

[HttpGet]
public string TestString()
{
  return "[HttpGet]TestString()";
} 

特性有:[HttpGet]、[HttpPost]、[HttpPut]、[HttpDelete] 你可以根據你的需求使用

訪問URL:http://localhost:58088/api/Test/TestString/

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[HttpGet]TestString()</string>

你還可以給方法匿名

[ActionName("TS")]
[HttpGet]
public string TestString()
{
  return $@"[ActionName(TS)]+[HttpGet]TestString()";
}

這樣你就可以用TS來代替方法名了

訪問URL:http://localhost:58088/api/Test/TS/

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[ActionName(TS)]+[HttpGet]TestString()</string>

還有一種就更神奇了,就是特性路由


Web API 特性路由

上面我們講到過在App_Start文件夾下的WebApiConfig.cs文件裏面有這麼一行代碼

 config.MapHttpAttributeRoutes();

這個就是開啓特性路由的意思,系統默認開啓

升級TestController控制器

[Route("api/Test/TestRoute")]
[HttpGet]
public string TestRoute()
{
   return $@"使用特性路由+[HttpGet]TestRoute()";
}

訪問URL:http://localhost:58088/api/Test/TestRoute/

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用特性路由+[HttpGet]TestRoute()</string>

當然,依舊可以匿名

[Route("api/Test/TR")]
[HttpGet]
public string TestRoute()
{
    return $@"使用特性路由---匿名+[HttpGet]TR/TestRoute()";
}

訪問URL:http://localhost:58088/api/Test/TR/

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用特性路由---匿名+[HttpGet]TR/TestRoute()</string>

是不是很簡單  o(∩_∩)o 哈哈

使用帶參數的特性路由

[Route("api/Test/TestRoute/{id}")]
[HttpGet]
public string TestRoute(int id)
{
    return $@"使用帶參數的特性路由+[HttpGet]TestRoute(int id)傳參爲:{id}";
}

訪問URL:http://localhost:58088/api/Test/TestRoute/5

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用帶參數的特性路由+[HttpGet]TestRoute(int id)傳參爲:5</string>

 

使用帶參數類型約束的特性路由

[Route("api/Test/TestRoute/{id:int=5}")]
[HttpGet]
public string TestRoute(int id)
{
    return $@"使用帶參數類型約束的特性路由+[HttpGet]TestRoute(int id)傳參爲:{id}";
}

這裏約束可變部分{id}的取值必須是int類型。並且默認值是5.

訪問:http://localhost:58088/api/Test/TestRoute/

結果:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用帶參數類型約束的特性路由+[HttpGet]TestRoute(int id)傳參爲:5</string>

訪問:http://localhost:58088/api/Test/TestRoute/7

結果:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用帶參數類型約束的特性路由+[HttpGet]TestRoute(int id)傳參爲:7</string>

訪問:http://localhost:58088/api/Test/TestRoute/a

結果:

<Error>
<Message>
找不到與請求 URI“http://localhost:58088/api/Test/TestRoute/a”匹配的 HTTP 資源。
</Message>
<MessageDetail>在控制器“Test”上找不到與名稱“TestRoute”匹配的操作。</MessageDetail>
</Error>

這裏之所以會報錯,是因爲我們特性約束了id必須爲int類型

使用多參數的特性路由

[Route("api/Test/TestRoute/{name}/{age:int=1}")]
[HttpGet]
public string TestRoute(string name,int age)
{
    return $@"使用多參數的特性路由+[HttpGet]TestRoute(string name,int id){name}的年齡是{age}歲";
}

訪問:http://localhost:58088/api/Test/TestRoute/Peter/25

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
使用多參數的特性路由+[HttpGet]TestRoute(string name,int id)Peter的年齡是25歲
</string>

訪問:localhost:58088/api/Test/TestRoute/老吳/25

結果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
使用多參數的特性路由+[HttpGet]TestRoute(string name,int id)老吳的年齡是25歲
</string>

TestController.cs完整代碼

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

namespace HaoSiJiaWeb.Api
{
    public class TestController : ApiController
    {

        /// <summary>
        /// 方法名字前面增加處理請求的類型
        /// 訪問url:http://localhost:58088/api/Test/TestString/
        /// </summary>

        //public string GetTestString()
        //{
        //  return "GetTestString()";
        //} 


        /// <summary>
        /// 方法上面增加特性說明[HttpGet]
        /// 訪問url:http://localhost:58088/api/Test/TestString/
        /// </summary>
        //[HttpGet]
        // public string TestString()
        //{
        //  return "[HttpGet]TestString()";
        //} 


        /// <summary>
        /// 使用匿名特性[ActionName("TS")]
        /// 訪問url:http://localhost:58088/api/Test/TS/
        /// </summary>
        [ActionName("TS")]
        [HttpGet]
        public string TestString()
        {
            return $@"[ActionName(TS)]+[HttpGet]TestString()";
        }

        /// <summary>
        /// 使用特性路由
        /// 訪問URL:http://localhost:58088/api/Test/TestRoute/
        /// </summary> 
        //[Route("api/Test/TestRoute")]
        //[HttpGet]
        //public string TestRoute()
        //{
        //    return $@"使用特性路由+[HttpGet]TestRoute()";
        //}



        /// <summary>
        /// 使用特性路由---匿名
        /// 訪問URL:http://localhost:58088/api/Test/TR/
        /// </summary> 
        [Route("api/Test/TR")]
        [HttpGet]
        public string TestRoute()
        {
            return $@"使用特性路由---匿名+[HttpGet]TR/TestRoute()";
        }

        /// <summary>
        /// 使用帶參數的特性路由
        /// 訪問URL:http://localhost:58088/api/Test/TestRoute/5
        /// </summary> 
        //[Route("api/Test/TestRoute/{id}")]
        //[HttpGet]
        //public string TestRoute(int id)
        //{
        //    return $@"使用帶參數的特性路由+[HttpGet]TestRoute(int id)傳參爲:{id}";
        //}


        /// <summary>
        /// 使用帶參數類型約束的特性路由
        /// 訪問URL:http://localhost:58088/api/Test/TestRoute/5
        /// </summary> 
        [Route("api/Test/TestRoute/{id:int=5}")]
        [HttpGet]
        public string TestRoute(int id)
        {
            return $@"使用帶參數類型約束的特性路由+[HttpGet]TestRoute(int id)傳參爲:{id}";
        }

        /// <summary>
        /// 使用多參數的特性路由
        /// 訪問URL:http://localhost:58088/api/Test/TestRoute/Peter/25
        /// </summary> 
        [Route("api/Test/TestRoute/{name}/{age:int=1}")]
        [HttpGet]
        public string TestRoute(string name, int age)
        {
            return $@"使用多參數的特性路由+[HttpGet]TestRoute(string name,int id){name}的年齡是{age}歲";
        }

    }
}

 

 


特性路由-進階篇

在同一個控制器裏,我們爲了保證URL前面的路徑一致,我們需要這樣做

 

新建MoveRouteController.cs

我們新建一個MoveRouteController.cs的Web API控制器

在正式項目中,同一個控制器的所有的action的所有特性路由標識一個相同的前綴,這種做法並非必須,但這樣能夠增加url的可讀性。一般的做法是在控制器上面使用特性[RoutePrefix]來標識。

完整代碼:

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

namespace HaoSiJiaWeb.Api
{
    [RoutePrefix("api/MoveRoute")]
    public class MoveRouteController : ApiController
    { 
        /// <summary>
        /// 使用帶參數類型約束的特性路由
        /// 訪問URL:http://localhost:58088/api/MoveRoute/MRoute
        /// </summary> 
        [HttpGet]
        public string MRoute()
        {
            return $@" MRoute()";
        }

        /// <summary>
        /// 使用帶參數類型約束的特性路由
        /// 訪問URL:http://localhost:58088/api/MoveRoute/TestRoute
        /// </summary> 
        [Route("TestRoute/{id:int=5}")]
        [HttpGet]
        public string TestRoute(int id)
        {
            return $@"使用帶參數類型約束的特性路由+[HttpGet]TestRoute(int id)傳參爲:{id}";
        }
    }
}

我們在控制器頂部用[RoutePrefix("")]約束好URL開頭後,後面的[Route("")]直接寫action名稱即可,

請仔細看上面代碼標註裏的URL,你就會發現他的神奇


延伸閱讀

WebApiConfig.cs的路由配置說明

面我們提到了,新建一個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 ;
        }
    }

WebApiConfig.cs文件再增加一個路由

   config.Routes.MapHttpRoute(
           name: "DefaultApi3",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints:new { id = @"\d+" } 
            );

我們加入約束條件 constraints: new { id = @"\d+" } ,這就約束必須要匹配一到多個參數id

我們通過http://localhost:58088/api2/Order/1來訪問,得到結果:

 

 

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

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

而我們訪問http://localhost:58088/api2/Order/。結果:

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

   config.Routes.MapHttpRoute(
           name: "DefaultApi3",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints:new { id = @"\d*" } 
            );

http://localhost:58088/api2/Order/

這樣就OK了。

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


參考:

C#進階系列——WebApi 路由機制剖析:你準備好了嗎?

https://www.cnblogs.com/landeanfen/p/5501490.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章