新建項目的時候可以直接勾選
勾選,“確定”後你會發現,項目多了這些文件
一、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的時候介紹過特性路由,感興趣的可以點擊下面鏈接進行查看
二、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