ASP.NET WebAPI2第004天_請求內容回傳格式_客製化方法名稱_FromBody,FromUri用法
雖然預設跑出來是json
但其實都還是建議要透過Accept
設定好client side預期接收的格式
Accept indicates what kind of response from the server the client can accept.
可理解為發送端(client)希望能接收到的回應格式
Content-type always is about the content of the current request or response.
可理解為發送端(client or server)目前發出請求傳遞的資料格式
比方XML
發送的請求
1 2 3 | GET /api/products HTTP/1.1 Host: localhost:59877 Accept: application/xml |
請求回來的Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | GET http://localhost:59877/api/products: { "Network": { "addresses": { "local": { "address": "::1", "family": "IPv6", "port": 52394 }, "remote": { "address": "::1", "family": "IPv6", "port": 59877 } } }, "Request Headers": { "accept": "application/xml", "postman-token": "3590169d-af21-44c8-b536-42fae0088fac", "host": "localhost:59877", "connection": "keep-alive" }, "Response Headers": { "cache-control": "no-cache", "pragma": "no-cache", "content-type": "application/xml; charset=utf-8", "expires": "-1", "server": "Microsoft-IIS/10.0", "x-aspnet-version": "4.0.30319", "x-sourcefiles": "=?UTF-8?B?RDpcV2ViUHJvamVjdHNcV2ViQXBpXE15V2ViQVBJMl9UZXN0MFxNeVdlYkFQSTJfVGVzdDBcYXBpXHByb2R1Y3Rz?=", "x-powered-by": "ASP.NET", "date": "Mon, 13 Dec 2021 08:09:15 GMT", "content-length": "392" }, "Response Body": "<ArrayOfProduct xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/MyWebAPI2_Test0.Models\"><Product><Id>0</Id><Price>20</Price><ProductName>Apple</ProductName></Product><Product><Id>1</Id><Price>40</Price><ProductName>Banana</ProductName></Product><Product><Id>2</Id><Price>60</Price><ProductName>Orange</ProductName></Product></ArrayOfProduct>" } |
發送的請求
1 2 3 | GET /api/products HTTP/1.1 Host: localhost:59877 Accept: application/json |
請求回來的Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | GET http://localhost:59877/api/products: { "Network": { "addresses": { "local": { "address": "::1", "family": "IPv6", "port": 53622 }, "remote": { "address": "::1", "family": "IPv6", "port": 59877 } } }, "Request Headers": { "accept": "application/json", "postman-token": "194ecb74-86fb-4cc3-a51b-7bc921f43086", "host": "localhost:59877", "connection": "keep-alive" }, "Response Headers": { "cache-control": "no-cache", "pragma": "no-cache", "content-type": "application/json; charset=utf-8", "expires": "-1", "server": "Microsoft-IIS/10.0", "x-aspnet-version": "4.0.30319", "x-sourcefiles": "=?UTF-8?B?RDpcV2ViUHJvamVjdHNcV2ViQXBpXE15V2ViQVBJMl9UZXN0MFxNeVdlYkFQSTJfVGVzdDBcYXBpXHByb2R1Y3Rz?=", "x-powered-by": "ASP.NET", "date": "Mon, 13 Dec 2021 08:27:25 GMT", "content-length": "135" }, "Response Body": "[{\"Id\":0,\"ProductName\":\"Apple\",\"Price\":20.0},{\"Id\":1,\"ProductName\":\"Banana\",\"Price\":40.0},{\"Id\":2,\"ProductName\":\"Orange\",\"Price\":60.0}]" } |
客製化方法名稱
在預設產生的專案範本中其實可看到被規範要
命名固定的名稱Get,Post,Put,Delete
或者GetXXX,PostXXX,PutXXX,DeleteXXX (有固定關鍵字前綴)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody] string value) { } // PUT api/values/5 public void Put(int id, [FromBody] string value) { } // DELETE api/values/5 public void Delete(int id) { } } |
以Get為例
若我Products名稱改為Get也就是預設的
或者GetProducts
都是可以直接透過Url 路由: api/Products去訪問的
但當我一改為LoadProducts時候就會出錯
為了能夠讓方法客製化彈性我們只需增加[HttpGet]相關的Http Verbs修飾即可
那這裡可以再實驗Delete 跟 Post的狀況
首先一樣命名一個是屬於固定關鍵字前綴的
PostProduct
DeleteProduct
都屬於200系列
而若我們故意改成非PostXXX跟DeleteXXX 則效果
Post我這裡測試過若用AddXXX預設也可以成功識別為Post添加一筆
但RemoveXXX這個就會突發出現405 Method 無法識別
mapping不到HttpDelete
當把HttpDelete 屬性修飾補上後即可work 回傳的是200系列
將Put改成ModifyProduct不加HttpVerbs屬性修飾時候
也有類似狀況
當補加回[HttpPut]修飾後就能正常Work了
也因此建議
若要客製化對應HttpVerbs 的Method 名稱話
養成好習慣
第一種.統一都加上對應HttpVerbs的屬性修飾
[HttpGet]
[HttpPost]
[HttpPut]
[HttpDelete]
第一種方式的程式碼
WebApiConfig 採用預設路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace MyWebAPI2_Test0 { 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 } ); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | using MyWebAPI2_Test0.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace MyWebAPI2_Test0.Controllers { public class ProductsController : ApiController { static List<Product> products = new List<Product>() { new Product(){Id = 0,ProductName = "Apple",Price = 20}, new Product(){Id = 1,ProductName = "Banana",Price = 40}, new Product(){Id = 2,ProductName = "Orange",Price = 60} }; // GET: api/Products [HttpGet] public IHttpActionResult LoadProducts() { return Ok(products); } // GET: api/Products/5 [HttpGet] public Product GetSpecificProduct(int id) { return products[id]; } // POST: api/Products [HttpPost] public HttpResponseMessage AddProduct([FromBody] Product product) { products.Add(product); return new HttpResponseMessage(HttpStatusCode.Created); } // PUT: api/Products/5 [HttpPut] public void ModifyProduct([FromUri] int id, [FromBody] Product product) { products[id] = product; } // DELETE: api/Products/5 [HttpDelete] public void RemoveProduct(int id) { products.RemoveAt(id); } } } |
第二種.或是採用預設的固定HttpVerbs名稱Get,Post,Put,Delete
在上方加上對應含意[ActionName("自訂")]也可以
[ActionName("SelectAll")]
[ActionName("SelectByID")]
[ActionName("Add")]
[ActionName("Modify")]
[ActionName("Remove")]
第二種方式的程式碼
在WebApiConfig 調整路由
將原本的
routeTemplate: "api/{controller}/{id}"
改為
routeTemplate: "api/{controller}/{action}/{id}"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace MyWebAPI2_Test0 { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 設定和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | using MyWebAPI2_Test0.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace MyWebAPI2_Test0.Controllers { public class ProductsController : ApiController { static List<Product> products = new List<Product>() { new Product(){Id = 0,ProductName = "Apple",Price = 20}, new Product(){Id = 1,ProductName = "Banana",Price = 40}, new Product(){Id = 2,ProductName = "Orange",Price = 60} }; // GET: api/products/SelectAll [ActionName("SelectAll")] public IHttpActionResult Get() { return Ok(products); } // GET: api/products/SelectByID/1 [ActionName("SelectByID")] public Product Get(int id) { return products[id]; } // POST: api/products/Add [ActionName("Add")] public HttpResponseMessage Post([FromBody] Product product) { products.Add(product); return new HttpResponseMessage(HttpStatusCode.Created); } // PUT: api/products/Modify/2 [ActionName("Modify")] public void Put([FromUri] int id, [FromBody] Product product) { products[id] = product; } // DELETE: api/products/Remove/2 [ActionName("Remove")] public void Delete(int id) { products.RemoveAt(id); } } } |
一般第一種.可能較常見
FromBody,FromUri用法
以Put方法為例就有分為從Url傳參跟從FormBody傳參兩種形式
這時要區分就建議加上這兩種修飾
假設今天你想將資料全透過URL GET參數傳送
比方編輯更新
這時將Product DTO用[FromUri]標記修飾
原先的URL請求從
http://localhost:59877/api/products/1
改為
http://localhost:59877/api/products?id=1&ProductName=Cherry&Price=50
Ref:
Difference between the Accept and Content-Type HTTP headers
Custom Method Names in Web API
How to Post a Custom Named Method in Web Api ?
您好:
回覆刪除參考您的說明,目前GET與POST皆可正常執行(中斷點有進去),但put卻出現錯誤,中斷點也沒進去,請問這要如何除錯? 謝謝!
此錯誤表示伺服器上不存在此檔案或目錄。請建立檔案或目錄,然後再次嘗試要求。
IIS70Error=404