[ASP.NET] WebAPI Get 使用複雜型別
在談如何在Get下使用複雜型別之前,先來看個東西,下面的程式碼是ApiController的範本程式碼
public class ValuesController : 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)
{
}
}
可以注意到在Post & Put的方法參數有個關鍵字[FromBody],而Get & Delete則沒有,事實上沒有加[FromBody]則默認為[FromUri],[FromBody]表示由請求文件本體中取得資料,就像一般表單Post Submit一樣,取得資料的來源是由請求本體中取得,而[FromUri]則表示由URI中取得資料,就像在網址列中的所夾帶的參數,除此之外預設對於複雜型別也是由[FromBody]取得資料。
有了以上初步的認知之後,我們來看一下,在ApiController的範本程式碼裡,Get方法很單純只有一個參數的傳入且為簡單的int型別,所以我們可以用Http : // … / api / Values / 1 這樣的請求執行Get(int id)方法,但事實上並非每個設計都只有需要一個簡單型別參數就能搞定,有時我們可能需要2個或以上的參數才能決定我們要取得的特定一筆資料,這時您可以這樣做
路由設定改為接受二個參數,分別為{p1} & {p2}
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "webapi/{controller}/{p1}/{p2}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
而ApiController裡的Get方法則調整為
public string Get(String p1, String p2)
{
return p1 + "/" + p2;
}
執行結果如下
雖然這樣可以解決我們需要有多個參數的需求,不過當參數一多的話,設計上就不是那麼的方便,因此如果我們想要讓Get方法可以接受一個複雜型別的參數時,如下程式碼,EmpQueryParameter是一個我們自訂的型別,具有二個屬性,而Get方法的參數改為接受這個自訂型別
public class EmpQueryParameter
{
public String FirstName { get; set; }
public String LastName { get; set; }
}
public string Get(EmpQueryParameter parameter)
{
return parameter.FirstName + "/" + parameter.LastName;
}
接著我們把路由的設定改為如下的設定
void Application_Start(object sender, EventArgs e)
{
// 應用程式啟動時執行的程式碼
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterOpenAuth();
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "webapi/{controller}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
}
然後直接執行,由於我們的參數是一個複雜型別,因此我們試著在網址列輸入Http : // … / webapi / values ?firstname=ian&lastname=chen 的請求,結果你會發現出現錯誤 "並未將物件參考設定為物件的執行個體。"
為什麼會引發這個錯誤呢?在本文一開始筆者即提到了預設對於複雜型別是由[FromBody]取得資料,所以我們的請求雖然在網址列夾帶了上?firstname=ian&lastname=chen 了,但它並不會被取得,因此就會出現這個例外錯誤,此時我們只要把Get方法稍加修飾一下,在參數前面指定[FromUri] 關鍵字
public string Get([FromUri] EmpQueryParameter parameter)
{
return parameter.FirstName + "/" + parameter.LastName;
}
接著再執行一次,就可以看到順利取得參數值
在多參數需求下,使用複雜型別的好處在於,我們可以不需要因受限在路由的設定,而必須要很清楚的記得參數位置順序,並且也不用因為不特定的參數數量而導致路由規劃複雜化,如同上面的範例,即使我們把請求參數改為?lastname=chen&firstname=ian,順序相反時,對於結果也不會產生異常,在Mapping上是以參數名稱對應型別的屬性名稱,此外即使我們傳了一個不存在型別裡的屬性名稱參數值,也不會引發錯誤,該參數只會被忽略掉。因此在設計上會更佳方便及具有彈性。
By No.18