正文前端
前言:還記得剛使用WebApi那會兒,被它的傳參機制折騰了很久,查閱了半天資料。現在,使用WebApi也有段時間了,今天就記錄下API接口傳參的一些方式方法,算是一個筆記,也但願能幫初學者少走彎路。本篇針對初初使用WebApi的同窗們,比較基礎,有興趣的且看看。web
WebApi系列文章面試
本篇打算經過get、post、put、delete四種請求方式分別談談基礎類型(包括int/string/datetime等)、實體、數組等類型的參數如何傳遞。ajax
對於取數據,咱們使用最多的應該就是get請求了吧。下面經過幾個示例看看咱們的get請求參數傳遞。json
[HttpGet] public string GetAllChargingData(int id, string name) { return "ChargingData" + id; }
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetAllChargingData", data: { id: 1, name: "Jim", bir: "1988-09-11"}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
參數截圖效果後端
這是get請求最基礎的參數傳遞方式,沒什麼特別好說的。api
若是咱們在get請求時想將實體對象作參數直接傳遞到後臺,是否可行呢?咱們來看看。跨域
public class TB_CHARGING { /// <summary> /// 主鍵Id /// </summary> public string ID { get; set; } /// <summary> /// 充電設備名稱 /// </summary> public string NAME { get; set; } /// <summary> /// 充電設備描述 /// </summary> public string DES { get; set; } /// <summary> /// 建立時間 /// </summary> public DateTime CREATETIME { get; set; } }
[HttpGet] public string GetByModel(TB_CHARGING oData) { return "ChargingData" + oData.ID; }
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
測試結果數組
由上圖可知,在get請求時,咱們直接將json對象當作實體傳遞後臺,後臺是接收不到的。這是爲何呢?咱們來看看對應的http請求
原來,get請求的時候,默認是將參數所有放到了url裏面直接以string的形式傳遞的,後臺天然接不到了。
緣由分析:還記得有面試題問過get和post請求的區別嗎?其中有一個區別就是get請求的數據會附在URL以後(就是把數據放置在HTTP協議頭中),而post請求則是放在http協議包的包體中。
根據園友們的提議,Get請求的時候能夠在參數裏面加上[FromUri]便可直接獲得對象。仍是貼上代碼:
var postdata = { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }; $.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetAllChargingData", data: postdata, success: function (data, status) { } });
[HttpGet] public string GetAllChargingData([FromUri]TB_CHARGING obj) { return "ChargingData" + obj.ID; }
獲得結果:
若是你不想使用[FromUri]這些在參數裏面加特性的這種「怪異」寫法,也能夠採用先序列化,再在後臺反序列的方式。
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; }
這樣在後臺獲得咱們序列化過的對象,再經過反序列化就能獲得對象。
在url裏面咱們能夠看到它自動給對象加了一個編碼:
至於還有園友們提到http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api的model binder這種方式,博主看了下,以爲略複雜。有興趣的也能夠試試。至於用哪種方式傳遞對象,園友們能夠自行選擇。
通常get請求不建議將數組做爲參數,由於咱們知道get請求傳遞參數的大小是有限制的,最大1024字節,數組裏面內容較多時,將其做爲參數傳遞可能會發生參數超限丟失的狀況。
爲何會說get請求「怪異」呢?咱們先來看看下面的兩種寫法對比。
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; }
這是標準寫法,後臺加[HttpGet],參數正常獲得:
爲了對比,我將[HttpGet]去掉,而後再調用
//[HttpGet] public string GetByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; }
貌似沒有任何問題!有人就想,那是否全部的get請求均可以省略掉[HttpGet]這個標註呢。咱們試試便知。
咱們把以前的方法名由GetByModel改爲FindByModel,這個再正常不過了,不少人查詢就不想用Get開頭,還有直接用Query開頭的。這個有什麼關係嗎?有沒有關係,咱們以事實說話。
$.ajax({ type: "get", url: "http://localhost:27221/api/Charging/FindByModel", contentType: "application/json", data: { strQuery: JSON.stringify({ ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }) }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
[HttpGet] public string FindByModel(string strQuery) { TB_CHARGING oData = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(strQuery); return "ChargingData" + oData.ID; }
貌似又可行,沒有任何問題啊。根據上面的推論,咱們去掉[HttpGet]也是可行的,好,咱們註釋掉[HttpGet],運行起來試試。
結果是不進斷點,有些人不信,咱們在瀏覽器裏面看看http請求:
呵呵,這就奇怪了,就改了個方法名,至於這樣麼?還真至於!
博主的理解是:方法名以Get開頭,WebApi會自動默認這個請求就是get請求,而若是你以其餘名稱開頭而又不標註方法的請求方式,那麼這個時候服務器雖然找到了這個方法,可是因爲請求方式不肯定,因此直接返回給你405——方法不被容許的錯誤。
最後結論:全部的WebApi方法最好是加上請求的方式([HttpGet]/[HttpPost]/[HttpPut]/[HttpDelete]),不要偷懶,這樣既能防止相似的錯誤,也有利於方法的維護,別人一看就知道這個方法是什麼請求。
這也就是爲何不少人在園子裏面問道爲何方法名不加[HttpGet]就調用不到的緣由!
在WebApi的RESETful風格里面,API服務的增刪改查,分別對應着http的post/delete/put/get請求。咱們下面就來講說post請求參數的傳遞方式。
post請求的基礎類型的參數和get請求有點不同,咱們知道get請求的參數是經過url來傳遞的,而post請求則是經過http的請求體中傳過來的,WebApi的post請求也須要從http的請求體裏面去取參數。
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { NAME: "Jim" }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } } });
[HttpPost] public bool SaveData(string NAME) { return true; }
這是一種看上去很是正確的寫法,但是實際狀況是:
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { "": "Jim" }, success: function (data, status) {} });
[HttpPost] public bool SaveData([FromBody]string NAME) { return true; }
這是一種另許多人頭痛的寫法,可是沒辦法,這樣確實能獲得咱們的結果:
咱們通常的經過url取參數的機制是鍵值對,即某一個key等於某一個value,而這裏的FromBody和咱們通常經過url取參數的機制則不一樣,它的機制是=value,沒有key的概念,而且若是你寫了key(好比你的ajax參數寫的{NAME:"Jim"}),後臺反而獲得的NAME等於null。不信你能夠試試。
上面講的都是傳遞一個基礎類型參數的狀況,那麼若是咱們須要傳遞多個基礎類型呢?按照上面的推論,是否能夠([FromBody]string NAME, [FromBody]string DES)這樣寫呢。試試便知。
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { "": "Jim","":"備註" }, success: function (data, status) {} });
[HttpPost] public bool SaveData([FromBody]string NAME, [FromBody] string DES) { return true; }
獲得結果
這說明咱們沒辦法經過多個[FromBody]裏面取值,此法失敗。
既然上面的辦法行不通,那咱們如何傳遞多個基礎類型的數據呢?不少的解決辦法是新建一個類去包含傳遞的參數,博主以爲這樣不夠靈活,由於若是咱們先後臺每次傳遞多個參數的post請求都去新建一個類的話,咱們系統到時候會有多少個這種參數類?維護起來那是至關的麻煩的一件事!因此博主以爲使用dynamic是一個很不錯的選擇。咱們來試試。
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", contentType: 'application/json', data: JSON.stringify({ NAME: "Jim",DES:"備註" }), success: function (data, status) {} });
[HttpPost] public object SaveData(dynamic obj) { var strName = Convert.ToString(obj.NAME); return strName; }
經過dynamic動態類型能順利獲得多個參數,省掉了[FromBody]這個累贅,而且ajax參數的傳遞不用使用"無厘頭"的{"":"value"}這種寫法,有沒有一種小清新的感受~~有一點須要注意的是這裏在ajax的請求裏面須要加上參數類型爲Json,即 contentType: 'application/json', 這個屬性。
經過上文post請求基礎類型參數的傳遞,咱們瞭解到了dynamic的方便之處,爲了不[FromBody]這個累贅和{"":"value"}這種"無厘頭"的寫法。博主推薦全部基礎類型使用dynamic來傳遞,方便解決了基礎類型一個或多個參數的傳遞,示例如上文。若是園友們有更好的辦法,歡迎討論。
上面咱們經過dynamic類型解決了post請求基礎類型數據的傳遞問題,那麼當咱們須要傳遞一個實體做爲參數該怎麼解決呢?咱們來看下面的代碼便知:
$.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", data: { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }, success: function (data, status) {} });
[HttpPost] public bool SaveData(TB_CHARGING oData) { return true; }
獲得結果
原理解釋:使用實體做爲參數的時候,前端直接傳遞普通json,後臺直接使用對應的類型去接收便可,不用FromBody。可是這裏須要注意的一點就是,這裏不能指定contentType爲appplication/json,不然,參數沒法傳遞到後臺。咱們來看看它默認的contentType是什麼:
爲了弄清楚緣由,博主查了下http的Content-Type的類型。看到以下說明:
也就是說post請求默認是將表單裏面的數據的key/value形式發送到服務,而咱們的服務器只須要有對應的key/value屬性值的對象就能夠接收到。而若是使用application/json,則表示將前端的數據以序列化過的json傳遞到後端,後端要把它變成實體對象,還須要一個反序列化的過程。按照這個邏輯,那咱們若是指定contentType爲application/json,而後傳遞序列化過的對象應該也是能夠的啊。博主好奇心重,仍是打算一試到底,因而就有了下面的代碼:
var postdata = { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }; $.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", contentType: 'application/json', data: JSON.stringify(postdata), success: function (data, status) {} });
[HttpPost] public bool SaveData(TB_CHARGING lstCharging) { return true; }
獲得結果:
嘗試成功,也就是說,兩種寫法都是可行的。若是你指定了contentType爲application/json,則必需要傳遞序列化過的對象;若是使用post請求的默認參數類型,則前端直接傳遞json類型的對象便可。
有些時候,咱們須要將基礎類型和實體一塊兒傳遞到後臺,這個時候,咱們神奇的dynamic又派上用場了。
var postdata = { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }; $.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", contentType: 'application/json', data: JSON.stringify({ NAME:"Lilei", Charging:postdata }), success: function (data, status) {} });
[HttpPost] public object SaveData(dynamic obj) { var strName = Convert.ToString(obj.NAME); var oCharging = Newtonsoft.Json.JsonConvert.DeserializeObject<TB_CHARGING>(Convert.ToString(obj.Charging)); return strName; }
獲得結果:
原理也不用多說,同上。
var arr = ["1", "2", "3", "4"]; $.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", contentType: 'application/json', data: JSON.stringify(arr), success: function (data, status) { } });
[HttpPost] public bool SaveData(string[] ids) { return true; }
獲得結果:
var arr = [ { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }, { ID: "2", NAME: "Lilei", CREATETIME: "1990-12-11" }, { ID: "3", NAME: "Lucy", CREATETIME: "1986-01-10" } ]; $.ajax({ type: "post", url: "http://localhost:27221/api/Charging/SaveData", contentType: 'application/json', data: JSON.stringify(arr), success: function (data, status) {} });
[HttpPost] public bool SaveData(List<TB_CHARGING> lstCharging) { return true; }
獲得結果:
上面寫了那麼多,都是經過前端的ajax請求去作的,咱們知道,若是調用方不是web項目,好比Android客戶端,可能須要從後臺發送http請求來調用咱們的接口方法,若是咱們經過後臺去發送請求是否也是可行的呢?咱們以實體對象做爲參數來傳遞寫寫代碼試一把。
public void TestReques() { //請求路徑 string url = "http://localhost:27221/api/Charging/SaveData"; //定義request並設置request的路徑 WebRequest request = WebRequest.Create(url); request.Method = "post"; //初始化request參數 string postData = "{ ID: \"1\", NAME: \"Jim\", CREATETIME: \"1988-09-11\" }"; //設置參數的編碼格式,解決中文亂碼 byte[] byteArray = Encoding.UTF8.GetBytes(postData); //設置request的MIME類型及內容長度 request.ContentType = "application/json"; request.ContentLength = byteArray.Length; //打開request字符流 Stream dataStream = request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); //定義response爲前面的request響應 WebResponse response = request.GetResponse(); //獲取相應的狀態代碼 Console.WriteLine(((HttpWebResponse)response).StatusDescription); //定義response字符流 dataStream = response.GetResponseStream(); StreamReader reader = new StreamReader(dataStream); string responseFromServer = reader.ReadToEnd();//讀取全部 Console.WriteLine(responseFromServer); }
當代碼運行到request.GetResponse()這一句的時候,API裏面進入斷點
嘗試成功。
WebApi裏面put請求通常用於對象的更新。它和用法和post請求基本相同。一樣支持[FromBody],一樣可使用dynamic。
$.ajax({ type: "put", url: "http://localhost:27221/api/Charging/Update", contentType: 'application/json', data: JSON.stringify({ ID: "1" }), success: function (data, status) {} });
[HttpPut] public bool Update(dynamic obj ) { return true; }
和post請求相同。
和post請求相同。
顧名思義,delete請求確定是用於刪除操做的。參數傳遞機制和post也是基本相同。下面簡單給出一個例子,其餘狀況參考post請求。
var arr = [ { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" }, { ID: "2", NAME: "Lilei", CREATETIME: "1990-12-11" }, { ID: "3", NAME: "Lucy", CREATETIME: "1986-01-10" } ]; $.ajax({ type: "delete", url: "http://localhost:27221/api/Charging/OptDelete", contentType: 'application/json', data: JSON.stringify(arr), success: function (data, status) {} });
[HttpDelete] public bool OptDelete(List<TB_CHARGING> lstChargin) { return true; }
以上比較詳細的總結了WebApi各類請求的各類參數傳遞。每種狀況都是博主實際代碼測試過的,內容不難,但若是剛接觸這麼些東西仍是須要一點時間去熟悉的,在此作個總結,但願能幫到剛剛接觸WebApi的園友們。若是本文能幫到你,不妨推薦下,您的推薦是博主繼續總結的動力!
最近打算作點本身的東西出來,將博客裏面的一些好的技術融合進去。有項目合做的小夥伴趕快聯繫博主吧!
本文原創出處:http://www.cnblogs.com/landeanfen/
歡迎各位轉載,可是未經做者本人贊成,轉載文章以後必須在文章頁面明顯位置給出做者和原文鏈接,不然保留追究法律責任的權利!