[筆記][WebAPI] ASP.NET 透過 HttpClient 存取 WebAPI 範例

一直以來在使用或測試開發的WebAPI,都是透過html Client的jQuery Ajax或者Google Chrome的工具【Dev HTTP Client】。不過最近小喵有個需求要在ASP.NET的系統中,在Server來存取Web API,於是著手來尋找相關的寫法,發現網路上這類範例還蠻分散的。小喵就整理一下,透過 HttpClient 存取 WebAPI ,並且可以傳送指定的 Head 。以下來看看相關範例~

緣起

一直以來在使用或測試開發的WebAPI,都是透過html Client的jQuery Ajax或者Google Chrome的工具【Dev HTTP Client】。不過最近小喵有個需求要在ASP.NET的系統中,在Server來存取Web API,於是著手來尋找相關的寫法,發現網路上這類範例還蠻分散的。小喵就整理一下,透過 HttpClient 存取 WebAPI ,並且可以傳送指定的 Head 。以下來看看相關範例~

 

GET

先從最基本的Get方法來測試起

這邊的範例有兩種,一個是透過 HttpClient 的【GetAsync】,另一個是搭配【HttpRequestMessage】+【SendAsync】的方式,以下就分別來看這兩種方式

 

GET方式一:GetAsync

首先是最基本的 GetAsync,在使用前我們畫面先準備一個輸入WebAPI 的Textbox,以及一個按鈕,希望按下按鈕後,根據TextBox輸入的WebAPI來取得資料,希望傳回JSON的相關內容,把傳回的內容放在一個TextBox TextMode=MultiLine

畫面安排:

URI:<asp:TextBox ID="txtURI" runat="server" Width="631px" Text="http://localhost:1823/api/products"></asp:TextBox>
<br />

Get:<br />
<asp:Button ID="btnGet1" runat="server" Text="簡單的Get" /><br />

<hr />
<asp:TextBox ID="txtRlt" runat="server" TextMode="MultiLine" Height="162px" Width="741px"></asp:TextBox>

接著就來撰寫這個按鈕按下的動作,相關程式碼如下:

'宣告HttpClient
Dim client As New HttpClient()

'宣告ResponseMessage來承接回傳的內容
Dim rspn As HttpResponseMessage

'WebAPI的Uri
Dim uriWebApi As New Uri(Me.txtURI.Text)

'透過GetAsync非同步呼叫WebAPI,結果傳給ResponseMessage
rspn = Await client.GetAsync(uriWebApi)
'確認成功
rspn.EnsureSuccessStatusCode()

'讀取回傳的內容
Dim Content As String = Await rspn.Content.ReadAsStringAsync()
'顯示回傳的內容
Me.txtRlt.Text = Content

問題排除

不過這時候會發現,部分程式碼下方會出現一些小蝌蚪,原因是因為我們使用非同步的方式,那麼相對的Onclick的Sub也要對應為非同步,這部分可以由Visual Studio來幫我們修正

uwp01

 

 

修正後,會發現我們的Button Click的Sub多了Async的設定

Protected Async Sub btnGet1_Click(sender As Object, e As EventArgs) Handles btnGet1.Click

接著運行看看,又會出現如下的錯誤訊息:

uwp02

這部分一樣是因為使用了非同步,所以在aspx的page設定中,需加上【Async="true"】,這樣就可以正常的讀取WebAPI囉

 

PS.如果WebAPI讀取有問題,那麼需要針對WebAPI設定為可以跨網預存取,這個部分請參考以下 MVP KKBruce 的這篇

http://blog.kkbruce.net/2013/05/aspnet-web-api-cors-preview-full-featured-profiling.html#.Uqfx4PQW0XU

 

 

GET方式二:HttpRequestMessage + SendAsync 傳遞自訂 Head

在WebAPI使用過程中,我們可能還會透過Header來傳送一些資訊,因此我們再來測試看看,HttpClient 的 SendAsync 搭配 HttpRequestMessage來做GET

這裡我們先在畫面上安排輸入多筆Head的部分

首先我們先定義myHead物件,然後透過物件集合的搭配ViewState將輸入的內容放在GridView裡面

myHead類別:

<Serializable> _
Public Class myHead
    Public Property HeadName As String = ""
    Public Property HeadValue As String = ""
End Class

在我們的Code File中宣告Heads物件集合

'定義Head物件集合
Dim Heads As List(Of myHead)

在PageLoad事件中準備物件集合

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    '從ViewState取得Heads物件集合
    Heads = ViewState("Heads")

    If Heads Is Nothing Then
        '如果是空的(ViewState是空的),New一個物件集合
        Heads = New List(Of myHead)
        '將物件集合存入ViewState
        ViewState("Heads") = Heads
    End If

End Sub

畫面中安排維護Heads的相關控制項:

Heads:
<table>
	<thead>
		<tr>
			<td>
				<asp:TextBox ID="txtHeadName" runat="server"></asp:TextBox>
			</td>
			<td>:</td>
			<td>
				<asp:TextBox ID="txtHeadValue" runat="server"></asp:TextBox>
			</td>
			<td>
				<asp:Button ID="btnAddHead" runat="server" Text="加入Head" />
			</td>
		</tr>
	</thead>
</table>
<asp:GridView ID="gvHeads" runat="server" AutoGenerateColumns="False">
	<Columns>
		<asp:CommandField ShowDeleteButton="True" />
		<asp:BoundField DataField="HeadName" HeaderText="HeadName" SortExpression="HeadName" />
		<asp:BoundField DataField="HeadValue" HeaderText="HeadValue" SortExpression="HeadValue" />
	</Columns>
</asp:GridView>

編輯Heads的部分,這裡不是重點,就直接表過不詳提

Private Sub gvHeadReBind()
    ViewState("Heads") = Heads
    Me.gvHeads.DataSource = Heads
    Me.gvHeads.DataBind()
End Sub

Protected Sub btnAddHead_Click(sender As Object, e As EventArgs) Handles btnAddHead.Click
    Dim tHead As New myHead
    tHead.HeadName = Me.txtHeadName.Text
    tHead.HeadValue = Me.txtHeadValue.Text
    Heads.Add(tHead)
    gvHeadReBind()
End Sub

Protected Sub gvHeads_RowDeleting(sender As Object, e As GridViewDeleteEventArgs) Handles gvHeads.RowDeleting
    Dim idx As Integer = e.RowIndex
    Heads.RemoveAt(idx)
    gvHeadReBind()
End Sub

再來才是重點,透過 HttpClient 的 Hy 搭配 HttpRequestMessage 來處理 GET

'宣告HttpClient
Dim client As New HttpClient()
'宣告ResponseMessage來承接回傳的內容
Dim rspn As HttpResponseMessage
'WebAPI的Uri
Dim uriWebApi As New Uri(Me.txtURI.Text)
'定義RequestMessage
Dim rq As New HttpRequestMessage()
'設定Request的Uri
rq.RequestUri = uriWebApi
'逐一讀取Head
For Each tHead As myHead In Heads
    rq.Headers.Add(tHead.HeadName, tHead.HeadValue)
Next
'透過SendAsync非同步呼叫WebAPI,結果傳給ResponseMessage
rspn = Await client.SendAsync(rq)
'確認成功
rspn.EnsureSuccessStatusCode()
'讀取回傳的內容
Dim Content As String = Await rspn.Content.ReadAsStringAsync()
'顯示回傳的內容
Me.txtRlt.Text = Content

這樣就可以搭配自訂的 Head 來GET(讀取) WebAPI

 

POST

接下來測試POST的部分。POST的部分需要一個Body放置要送出的內容。

Body:<br />
<asp:TextBox ID="txtBody" runat="server" TextMode="MultiLine" Height="134px" Width="735px"></asp:TextBox>

 

PS.在REST的基本來看POST主要是用來做Insert,不過其實POST也不一定就只做Insert,我們還是可以透過POST來做複雜條件的GET或者複雜條件、多筆的Update,不過關於這部分屬於WebAPI怎麼寫的範圍,這邊就表過不提。

 

一樣的POST可以有兩種方式,一個是透過【HttpClient的PostAsync】,另一個是使用【SendAsync】,以下來分別列出相關範例:

 

POST : PostAsync

'宣告HttpClient
Dim client As New HttpClient()
'宣告要送出的Body內容
Dim hContent As HttpContent = New StringContent(Me.txtBody.Text)
'設定Body內容的格式
hContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
'WebAPI的Uri
Dim uriWebAPI As New Uri(Me.txtURI.Text)
'宣告ResponseMessage來承接回傳的內容
Dim rspn As HttpResponseMessage = Await client.PostAsync(uriWebAPI, hContent)
'讀取回傳的內容,並顯示在txtRlt中
Me.txtRlt.Text = Await rspn.Content.ReadAsStringAsync

 

POST : SendAsync + Heads

 

'宣告HttpClient
Dim client As New HttpClient()
'宣告ResponseMessage來承接回傳的內容
Dim rspn As HttpResponseMessage
'WebAPI的Uri
Dim uriWebApi As New Uri(Me.txtURI.Text)
'定義RequestMessage
Dim rq As New HttpRequestMessage()
'設定Request的Uri
rq.RequestUri = uriWebApi

'逐一設定Header內容
For Each tHead As myHead In Heads
    rq.Headers.Add(tHead.HeadName, tHead.HeadValue)
Next

'設定Request的Method為Post
rq.Method = HttpMethod.Post

'宣告要送出的Body內容
Dim hContent As HttpContent = New StringContent(Me.txtBody.Text)
'設定Body內容的格式
hContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
'設定RequestMessage的Content是hContent
rq.Content = hContent
'宣告ResponseMessage來承接回傳的內容
rspn = Await client.SendAsync(rq)
'確認成功
rspn.EnsureSuccessStatusCode()
'讀取回傳的內容
Dim rtnContent As String = Await rspn.Content.ReadAsStringAsync()
'顯示回傳的內容
Me.txtRlt.Text = rtnContent

 

 

PUT

PUT的部分,一樣會有個Body來放要更新的內容,這部分就直接套用POST那部分所用道的txtBody這個控制項即可

PUT一樣這邊示範兩種方式:分別是HttpClient的【PutAsync】、【SendAsync】

 

PUT : PutAsync

Protected Async Sub btnPut1_Click(sender As Object, e As EventArgs) Handles btnPut1.Click
    '宣告HttpClient
    Dim client As New HttpClient()
    '宣告要送出的Body內容
    Dim hContent As HttpContent = New StringContent(Me.txtBody.Text)
    '設定Body內容的格式
    hContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
    'WebAPI的Uri
    Dim uriWebAPI As New Uri(Me.txtURI.Text)
    '宣告ResponseMessage來承接回傳的內容
    Dim rspn As HttpResponseMessage = Await client.PutAsync(uriWebAPI, hContent)
    '讀取回傳的內容,並顯示在txtRlt中
    Me.txtRlt.Text = Await rspn.Content.ReadAsStringAsync

End Sub

 

PUT : SendAsync + Heads

Protected Async Sub btnPutHead_Click(sender As Object, e As EventArgs) Handles btnPutHead.Click
    '宣告HttpClient
    Dim client As New HttpClient()
    '宣告ResponseMessage來承接回傳的內容
    Dim rspn As HttpResponseMessage
    'WebAPI的Uri
    Dim uriWebApi As New Uri(Me.txtURI.Text)
    '定義RequestMessage
    Dim rq As New HttpRequestMessage()
    '設定Request的Uri
    rq.RequestUri = uriWebApi

    '逐一設定Header內容
    For Each tHead As myHead In Heads
        rq.Headers.Add(tHead.HeadName, tHead.HeadValue)
    Next

    '設定Request的Method為Put
    rq.Method = HttpMethod.Put

    '宣告要送出的Body內容
    Dim hContent As HttpContent = New StringContent(Me.txtBody.Text)
    '設定Body內容的格式
    hContent.Headers.ContentType = New MediaTypeHeaderValue("application/json")
    '設定RequestMessage的Content是hContent
    rq.Content = hContent
    '宣告ResponseMessage來承接回傳的內容
    rspn = Await client.SendAsync(rq)
    '確認成功
    rspn.EnsureSuccessStatusCode()
    '讀取回傳的內容
    Dim rtnContent As String = Await rspn.Content.ReadAsStringAsync()
    '顯示回傳的內容
    Me.txtRlt.Text = rtnContent
End Sub

 

DELETE

最後是Delete

Delete的部分就指示範簡單的刪除,如果要透過SendAsync來刪除,大概與上面的差不多。

 

Delete : DeleteAsync

Protected Async Sub btnDel1_Click(sender As Object, e As EventArgs) Handles btnDel1.Click
    '宣告HttpClient
    Dim client As New HttpClient()
    '宣告ResponseMessage來承接回傳的內容
    Dim rspn As HttpResponseMessage
    'WebAPI的Uri
    Dim uriWebApi As New Uri(Me.txtURI.Text)
    '透過GetAsync非同步呼叫WebAPI,結果傳給ResponseMessage
    rspn = Await client.DeleteAsync(uriWebApi)
    '確認成功
    rspn.EnsureSuccessStatusCode()
    '讀取回傳的內容
    Dim Content As String = Await rspn.Content.ReadAsStringAsync()
    '顯示回傳的內容
    Me.txtRlt.Text = Content
End Sub

 

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6)