關於 PUT 要求在用戶端的程式設計與使用方式,與使用 POST 要求是相同的,差異在於,當您要進行 PUT 要求呼叫 Web API 的時候,需要使用 HttpClient.PutAsync() 方法,而之前介紹的 POST,則是使用 HttpClient.PostAsync() 方法;當然,對於後端的 Web API 伺服器上的程式開發,也是會有差異的,您需要分別使用不同的屬性 (Attribute) 來標示出哪個控制器的動作(Action 或稱方法)要套用 POST 或者 POST。
了解更多關於 [HttpClient Class] 的使用方式
了解更多關於 [使用 async 和 await 進行非同步程式設計] 的使用方式
使用 PUT 要求與 JSON 編碼內容 呼叫 Web API
在這裡,我們使用
application/json
編碼格式作為呼叫 PUT 要求。因此,我們需要藉由 JSON.NET 這個套件,幫助我們將要傳送過去的 .NET 物件,序列化成為 JSON 編碼格式的內容;var fooJSON = JsonConvert.SerializeObject(apiData);
這個敘述,就是做到這樣的目的。
我們使用
new StringContent(fooJSON, Encoding.UTF8, "application/json")
表示是,建立一個 fooContent 物件,從建立物件所使用的建構函式參數可以看出,我們要建立一個 application/json
編碼格式的 StringContent
物件
不過,因為
StringContent
類別以實作 IDisposable
介面,因此,我們使用 using 陳述式將其包起來,讓這個物件於使用完後,可以儘快的釋放掉非受管理的記憶體資源。
最後,我們就可以呼叫
await client.PutAsync(fooFullUrl, fooContent);
方法,將要傳送過去的資料,使用 application/json
編碼格式,送到 Web API 主機上對應的控制器與動作方法內。private static async Task<APIResult> JsonPutAsync(APIData apiData)
{
APIResult fooAPIResult;
using (HttpClientHandler handler = new HttpClientHandler())
{
using (HttpClient client = new HttpClient(handler))
{
try
{
#region 呼叫遠端 Web API
string FooUrl = $"http://vulcanwebapi.azurewebsites.net/api/Values";
HttpResponseMessage response = null;
#region 設定相關網址內容
var fooFullUrl = $"{FooUrl}";
// Accept 用於宣告客戶端要求服務端回應的文件型態 (底下兩種方法皆可任選其一來使用)
//client.DefaultRequestHeaders.Accept.TryParseAdd("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Content-Type 用於宣告遞送給對方的文件型態
//client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
var fooJSON = JsonConvert.SerializeObject(apiData);
using (var fooContent = new StringContent(fooJSON, Encoding.UTF8, "application/json"))
{
response = await client.PutAsync(fooFullUrl, fooContent);
}
#endregion
#endregion
#region 處理呼叫完成 Web API 之後的回報結果
if (response != null)
{
if (response.IsSuccessStatusCode == true)
{
// 取得呼叫完成 API 後的回報內容
String strResult = await response.Content.ReadAsStringAsync();
fooAPIResult = JsonConvert.DeserializeObject<APIResult>(strResult, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
}
else
{
fooAPIResult = new APIResult
{
Success = false,
Message = string.Format("Error Code:{0}, Error Message:{1}", response.StatusCode, response.RequestMessage),
Payload = null,
};
}
}
else
{
fooAPIResult = new APIResult
{
Success = false,
Message = "應用程式呼叫 API 發生異常",
Payload = null,
};
}
#endregion
}
catch (Exception ex)
{
fooAPIResult = new APIResult
{
Success = false,
Message = ex.Message,
Payload = ex,
};
}
}
}
return fooAPIResult;
}
觸發的 Web API 動作
這個範例中,將會指向 URL
http://vulcanwebapi.azurewebsites.net/api/values
,此時,將會觸發 Web API 伺服器上的 Values 控制器(Controller)的 public APIResult Put(int id, [FromBody]APIData value)
動作(Action),其該動作的原始碼如下所示。
這個 Web API 動作,將會回傳一個 APIData 的 JSON 資料。
[HttpPut]
public APIResult Put(int id, [FromBody]APIData value)
{
APIResult foo;
if (value.Id == 777)
{
foo = new APIResult()
{
Success = true,
Message = "透過 Put 方法,接收到 Id=777 資料",
Payload = value
};
}
else
{
foo = new APIResult()
{
Success = false,
Message = "無法發現到指定的 ID",
Payload = null
};
}
return foo;
}
進行測試
在程式進入點函式,我們建立一個
APIData
型別的物件,接著,設定該物件的相關屬性,這些屬性值,是我們要傳送到遠端伺服器端的資料,由上面的程式碼中,我們可以知道,當 Id 這個屬性值為 777 的時候,該 Web API 動作將會回覆通知,這次的呼叫是成功的,否則,會回覆此次 Web API 呼叫失敗。static void Main(string[] args)
{
var fooAPIData = new APIData()
{
Id = 777,
Name = "VulcanSource",
};
var foo = JsonPutAsync(fooAPIData).Result;
Console.WriteLine($"使用 JSON 格式與使用 Put 方法呼叫 Web API 的結果");
Console.WriteLine($"結果狀態 : {foo.Success}");
Console.WriteLine($"結果訊息 : {foo.Message}");
Console.WriteLine($"Payload : {foo.Payload}");
Console.WriteLine($"");
Console.WriteLine($"Press any key to Exist...{Environment.NewLine}");
Console.ReadKey();
fooAPIData = new APIData()
{
Id = 123,
Name = "VulcanSource",
};
foo = JsonPutAsync(fooAPIData).Result;
Console.WriteLine($"使用 JSON 格式與使用 Put 方法呼叫 Web API 的結果");
Console.WriteLine($"結果狀態 : {foo.Success}");
Console.WriteLine($"結果訊息 : {foo.Message}");
Console.WriteLine($"Payload : {foo.Payload}");
Console.WriteLine($"");
Console.WriteLine($"Press any key to Exist...{Environment.NewLine}");
Console.ReadKey();
}
執行結果
這個測試將會輸出底下內容
使用 JSON 格式與使用 Put 方法呼叫 Web API 的結果
結果狀態 : True
結果訊息 : 透過 Put 方法,接收到 Id=777 資料
Payload : {
"id": 777,
"name": "VulcanSource",
"filename": null
}
Press any key to Exist...
使用 JSON 格式與使用 Put 方法呼叫 Web API 的結果
結果狀態 : False
結果訊息 : 無法發現到指定的 ID
Payload :
Press any key to Exist...
HTTP 傳送與接收原始封包
讓我們來看看,這個 Web API 的呼叫動作中,在請求 (Request) 與 反應 (Response) 這兩個階段,會在網路上傳送了那些 HTTP 資料
- 請求 (Request)從第一行的 Http 原始封包內容中,我們看到了,這裡是請求一個遠端 Web API 之 PUT 的請求呼叫;在這裡的第三行中,您將會看到有
Content-Type
的 Http Header 欄位,他的值設定為application/json; charset=utf-8
,這表示了這次的 PUT 要求動作,將會使用 JSON 編碼的方式,將資料傳送到後端 Web API 伺服器上;會有這樣的結果產生,那是因為,我們有產生一個new StringContent(fooJSON, Encoding.UTF8, "application/json")
這樣的物件,並且使用 PutAsync 方法,將這個物件傳送到這個非同步方法內。Content-Length
這個 Http Header 欄位,C# 的 HttpClient 類別,會自動幫我們計算出,此次 PUTmultipart/form-data
編碼封包的總共大小。在最後一行,則是我們要傳送過去的物件之 JSON 編碼結果文字,在這裡,欄位 Id 的數值為 777。
PUT http://vulcanwebapi.azurewebsites.net/api/Values HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: vulcanwebapi.azurewebsites.net
Content-Length: 48
Expect: 100-continue
Connection: Keep-Alive
{"Id":777,"Name":"VulcanSource","Filename":null}
- 反應 (Response)
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=9d3635139ab6649f453417d1e9047b7ed7a79b7bef031b04afeb6a2c58b33d4e;Path=/;HttpOnly;Domain=vulcanwebapi.azurewebsites.net
Date: Sun, 22 Oct 2017 07:59:10 GMT
83
{"success":true,"message":"透過 Put 方法,接收到 Id=777 資料","payload":{"id":777,"name":"VulcanSource","filename":null}}
0
- 請求 (Request)從第一行的 Http 原始封包內容中,我們看到了,這裡是請求一個遠端 Web API 之 PUT 的請求呼叫;在這裡的第三行中,您將會看到有
Content-Type
的 Http Header 欄位,他的值設定為application/json; charset=utf-8
,這表示了這次的 PUT 要求動作,將會使用 JSON 編碼的方式,將資料傳送到後端 Web API 伺服器上;會有這樣的結果產生,那是因為,我們有產生一個new StringContent(fooJSON, Encoding.UTF8, "application/json")
這樣的物件,並且使用 PutAsync 方法,將這個物件傳送到這個非同步方法內。Content-Length
這個 Http Header 欄位,C# 的 HttpClient 類別,會自動幫我們計算出,此次 PUTmultipart/form-data
編碼封包的總共大小。在最後一行,則是我們要傳送過去的物件之 JSON 編碼結果文字,在這裡,欄位 Id 的數值為 123。
PUT http://vulcanwebapi.azurewebsites.net/api/Values HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: vulcanwebapi.azurewebsites.net
Content-Length: 48
Expect: 100-continue
{"Id":123,"Name":"VulcanSource","Filename":null}
- 反應 (Response)
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=9d3635139ab6649f453417d1e9047b7ed7a79b7bef031b04afeb6a2c58b33d4e;Path=/;HttpOnly;Domain=vulcanwebapi.azurewebsites.net
Date: Sun, 22 Oct 2017 07:59:12 GMT
48
{"success":false,"message":"無法發現到指定的 ID","payload":null}
0
相關文章索引
C# HttpClient WebAPI 系列文章索引
了解更多關於 [HttpClient Class] 的使用方式
關於 Xamarin 在台灣的學習技術資源
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程
application/x-www-form-urlencoded
/multipart/form-data
/application/json
,現在,我們要來看第三種 Http 的要求(之前已經介紹過 GET / POST 的用法),那就是 PUT 要求。