[ASP.NET] WebAPI Get 使用複雜型別

  • 15146
  • 0

[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;
}

執行結果如下

image

 

雖然這樣可以解決我們需要有多個參數的需求,不過當參數一多的話,設計上就不是那麼的方便,因此如果我們想要讓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 的請求,結果你會發現出現錯誤 "並未將物件參考設定為物件的執行個體。"

image

 

為什麼會引發這個錯誤呢?在本文一開始筆者即提到了預設對於複雜型別是由[FromBody]取得資料,所以我們的請求雖然在網址列夾帶了上?firstname=ian&lastname=chen 了,但它並不會被取得,因此就會出現這個例外錯誤,此時我們只要把Get方法稍加修飾一下,在參數前面指定[FromUri] 關鍵字

public string Get([FromUri] EmpQueryParameter parameter)
{
    return parameter.FirstName + "/" + parameter.LastName;
}

 

接著再執行一次,就可以看到順利取得參數值

image

 

 

在多參數需求下,使用複雜型別的好處在於,我們可以不需要因受限在路由的設定,而必須要很清楚的記得參數位置順序,並且也不用因為不特定的參數數量而導致路由規劃複雜化,如同上面的範例,即使我們把請求參數改為?lastname=chen&firstname=ian,順序相反時,對於結果也不會產生異常,在Mapping上是以參數名稱對應型別的屬性名稱,此外即使我們傳了一個不存在型別裡的屬性名稱參數值,也不會引發錯誤,該參數只會被忽略掉。因此在設計上會更佳方便及具有彈性。

 

若本文對您有所幫助,歡迎轉貼,但請在加註【轉貼】及來源出處,並在附上本篇的超連結,感恩您的配合囉。

By No.18