不得不說,Routing(路由)是整個ASP.NET Web API中最重要的部分,因為多數人無法很好的轉換平台,也是因為Routing實在有點複雜,而且有很多小地方要注意,程式設計師必須要兼顧Controller與Routing的設計和架構,以免一不小心的小錯誤卻造成大災難,本篇會以簡單易懂的範例來實作Routing,讓大家了解Routing的基礎運作方式。
這次,同樣是要管理應徵者的資料,請依照(二)ASP.NET Web API 2 - 建立第一個Web API一步一步地完成Model的設計,我們在本篇僅會對Controller以及WerbApiConfig.cs撰寫程式,其餘的一切都不會有變動,當然,最後仍會修改index.html網頁,真正對Routing的設計有感覺!
第一步:完成Model的設計後, 我們繼續編輯"CandidatesController.cs",除了原本回傳全部應徵者資料的方法外,我們要在新增三個搜尋應徵者資料的方法,其搜尋關鍵分別是:
- 姓名
- ID
- 姓名以及ID
//以姓名搜尋應徵者資料
public IHttpActionResult GetCandidateByNamea(string Name)
{
var myCandidate = Candidates.FirstOrDefault((c) => c.Name == Name);
if (myCandidate == null)
return NotFound();
else
return Ok(myCandidate);
}
//以ID搜尋應徵者資料
public IHttpActionResult GetCandidateById(string Id)
{
var myCandidate = Candidates.FirstOrDefault((c) => c.Id == Id);
if (myCandidate == null)
return NotFound();
else
return Ok(myCandidate);
}
//以姓名及ID搜尋應徵者資料
public IHttpActionResult GetCandidateByNameaAndId(string Name, string Id)
{
var myCandidate = Candidates.FirstOrDefault((c) => c.Name == Name && c.Id == Id);
if (myCandidate == null)
return NotFound();
else
return Ok(myCandidate);
}
可以發現,新增的這三個方法最大的不同,就是回傳值的型別"IHttpActionResult",由字面上的意思可以知道,IHttpActionResult代表HTTP動作的結果(狀態),所以我們可以在HttpStatusCode這個列舉中找到所有可用於IHttpActionResult的回傳值,最常使用的如下:
# | 方法名稱 | HTTP Status Code | 意義 |
1 | Ok | 200 | 要求成功 |
2 | NoContent | 204 | 已成功處理要求但回應是空白 |
3 | Unauthorized | 401 | 要求的資源需要驗證 |
4 | NotFound | 404 | 要求的資源不存在伺服器上 |
5 | InternalServerError | 500 | 伺服器端發生錯誤 |
另外,也可以發現,每個方法的參數值與我們以前寫函數的方式一樣,所以,在這個階段,不需要去改變任何的習慣。
第二步:接著我們要來設計Routing,打開App_Start/WebApiConfig.cs
,我們要針對每個方法設計一個專屬的Routing,如下:
//路由1
config.Routes.MapHttpRoute(
name: "GetCandidateByName",
routeTemplate: "api/{controller}/name/{name}",
defaults: new { name = RouteParameter.Optional }
);
//路由2
config.Routes.MapHttpRoute(
name: "GetCandidateById",
routeTemplate: "api/{controller}/id/{id}",
defaults: new { id = RouteParameter.Optional }
);
//路由3
config.Routes.MapHttpRoute(
name: "GetCandidateByNameAndId",
routeTemplate: "api/{controller}/{name}/{id}",
defaults: new { name = RouteParameter.Optional, id = RouteParameter.Optional }
);
每個路由的設定都有三個參數,分別為:
- name:路由的名稱
- routeTemplate:路由URI範本
- default:定義參數
在路由1中,先給他一個名稱叫做"GetCandidateByName",在Controller裡面也有一個一樣名稱的方法,這樣的設計只是讓我們比較容易分辨這個Routing到底是做什麼用的、與那些Controller方法有關係,名稱並不絕對一定要與Controller方法相同。
路由URI範本描述了這個Web API對外的URI長什麼樣子,例如"api/{controller}/name/{name}",翻譯一下就成為:"api/控制器名稱/name/參數name",如果套用到瀏覽器的網址上就成為:"http://domain:port/api/控制器名稱/name/參數name",這樣看起來就很簡單了吧!
最後就是定義參數,"RouteParameter.Optional"代表這個參數是可選用的,我們在呼叫Web API時不一定要送出這個參數,這也造就了路由3可以一個路由多個用途的原因!
我們來看看路由3,他的路由範本是"api/{controller}/{name}/{id}",且兩個參數都是可選用的,也就是不一定要傳入,所以可能的URI如下:
- api/{controller}/{name}/{id}
- api/{controller}/{name}
- api/{controller}
有人可能會問:「為什麼routeTemplate可以重複利用,並且以一個routeTemplate對應多個Controller方法,卻還要這樣一對一的去設計呢?」,沒錯,確實是可以這樣做,但若是你的Web API非常的多,到了一個很難管理的程度,你確定你會知道哪個routeTemplate對應到哪幾個Controller方法嗎?當然不知道,尤其那種大雜燴,所以有的時候我們還真的必須針對Controller方法設計專用的routeTemplate,一樣,這並不絕對,還是以規模、架構與經驗有關。
第三步:修改index.html,讓我們可以用姓名、ID來搜尋應徵者的名字
程式碼如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<title>Candidates</title>
<meta charset="utf-8" />
<script>
var apiurl = 'api/candidates';
$(document).ready(function () {
GetAllCandidates();
});
function GetAllCandidates() {
$.ajax({
url: apiurl,
success: function (result) {
$('#divCandidates').empty();
$.each(result, function (key, item) {
$('<li>' + item.Name + ', ' + item.Id + ', ' + item.Age + ', ' + item.Email + '</li>').appendTo('#divCandidates');
});
}
});
}
function SearchCandidateByName() {
var name = $('#candidateName').val();
$.ajax({
url: apiurl + '/name/' + name,
success: function (result) {
$('#divCandidates').empty();
$('<li>' + result.Name + ', ' + result.Id + ', ' + result.Age + ', ' + result.Email + '</li>').appendTo('#divCandidates');
},
error: function (jqXHR, exception) {
$('#divCandidates').empty();
alert('Nothing');
}
});
}
function SearchCandidateById() {
var id = $('#candidateId').val();
$.ajax({
url: apiurl + '/id/' + id,
success: function (result) {
$('#divCandidates').empty();
$('<li>' + result.Name + ', ' + result.Id + ', ' + result.Age + ', ' + result.Email + '</li>').appendTo('#divCandidates');
},
error: function (jqXHR, exception) {
$('#divCandidates').empty();
alert('Nothing');
}
});
}
function SearchCandidateByNameAndId() {
var name = $('#candidateName').val();
var id = $('#candidateId').val();
$.ajax({
url: apiurl + '/' + name+ '/' + id,
success: function (result) {
$('#divCandidates').empty();
$('<li>' + result.Name + ', ' + result.Id + ', ' + result.Age + ', ' + result.Email + '</li>').appendTo('#divCandidates');
},
error: function (jqXHR, exception) {
$('#divCandidates').empty();
alert('Nothing');
}
});
}
</script>
</head>
<body>
<div>
<h2>Candidates</h2>
<p>
Name:<input id="candidateName" type="text" />, ID:<input id="candidateId" type="text" />
<input type="button" value="Search by Name" onclick="SearchCandidateByName();" />
<input type="button" value="Search by Id" onclick="SearchCandidateById();" />
<input type="button" value="Search by Name and ID" onclick="SearchCandidateByNameAndId();" />
</p>
<p id="divCandidates"></p>
</div>
</body>
</html>
最後,遵照上一篇的往例,附上完整的範例專案檔,以便更全面、直觀的學習撰寫ASP.NET Web API。
範例下載連結:ASP.NET Web API 2 Practics02 - 1