[VB.NET] REST API⑪ ビューからWeb APIにPUT(Controller実装・Viewの追加と実行)
WebAPIにPUTリクエストをおこない、データ更新をおこなうビューを追加してみましょう。
※ VisualStudio2019
このサンプルでは、[VB.NET] REST API⑩ ビューからWeb APIにPOST#1で作成したコントローラー(ApiTestController・ViewTestController)とモデルクラス(Recordクラス・ViewTestParamクラス)を使用しています。
コントローラーのEditメソッドを実装
まずは APIのコントローラー「ApiTestController」の「PutValue」メソッドを実装します。
本来はデータベースやファイルに書き込む処理を書くことになりますが、
このサンプルでは、Viewからリクエスト > Controllerで処理 > Viewで結果を表示 という一連の流れを確認するだけにしたいので、レスポンスとして成功のメッセージを返すだけの、ダミー処理です。
また、今回はPUTリクエストを処理するため、GETメソッド(GetValue)の実装もおこないます。
このメソッドは、ビューに表示するレコードを取得するために必要です。
今回のサンプルでは、指定されたidを持つダミーレコードを返しています。
コード
Imports System.Net
Imports System.Web.Http
Namespace Controllers
Public Class ApiTestController
Inherits ApiController
' GET: api/ApiTest
Public Function GetValues() As IEnumerable(Of String)
Return New String() {"value1", "value2"}
End Function
' GET: api/ApiTest/5
Public Function GetValue(ByVal id As Integer) As Record
'レコード作成
Dim rec As New Record
rec.col1 = id
rec.col2 = "This is a test record."
rec.col3 = Now
Return rec
'Return "value"
End Function
' POST: api/ApiTest
Public Function PostValue(<FromBody()> ByVal value As Record) As System.Net.Http.HttpResponseMessage
Debug.Print(String.Format("col1:{0}", value.col1))
Debug.Print(String.Format("col2:{0}", value.col2))
Debug.Print(String.Format("col3:{0}", value.col3))
'登録処理(このサンプルはダミー処理)
Dim tbl As New List(Of Record)
tbl.Add(value)
'レスポンスメッセージ作成
Dim ret As System.Net.Http.HttpResponseMessage
ret = New System.Net.Http.HttpResponseMessage(HttpStatusCode.OK) '200
'成功メッセージを設定
Dim content As New Net.Http.StringContent("The record was created successfully !", Encoding.UTF8, "text/plain")
ret.Content = content
Return ret
End Function
' PUT: api/ApiTest/5
Public Function PutValue(ByVal id As Integer, ByVal value As Record) As System.Net.Http.HttpResponseMessage
Dim tbl As New List(Of Record) From {New Record() With {.col1 = id, .col2 = "old data", .col3 = New Date(2020, 12, 1)}}
'更新前の内容
Debug.Print(String.Format("更新前の内容"))
Debug.Print(String.Format("col1:{0}", tbl(0).col1))
Debug.Print(String.Format("col2:{0}", tbl(0).col2))
Debug.Print(String.Format("col3:{0}", tbl(0).col3))
'更新処理(このサンプルはダミー処理)
tbl(0).col1 = value.col1
tbl(0).col2 = value.col2
tbl(0).col3 = value.col3
'更新後の内容
Debug.Print(String.Format("更新後の内容"))
Debug.Print(String.Format("col1:{0}", tbl(0).col1))
Debug.Print(String.Format("col2:{0}", tbl(0).col2))
Debug.Print(String.Format("col3:{0}", tbl(0).col3))
'レスポンスメッセージ作成
Dim ret As System.Net.Http.HttpResponseMessage
ret = New System.Net.Http.HttpResponseMessage(HttpStatusCode.OK) '200
'成功メッセージを設定
Dim content As New Net.Http.StringContent("The record was updated successfully !", Encoding.UTF8, "text/plain")
ret.Content = content
Return ret
End Function
' DELETE: api/ApiTest/5
Public Sub DeleteValue(ByVal id As Integer)
End Sub
End Class
End Namespace
続いてビューのコントローラー「ViewTestController」の「Edit」メソッドを実装します。
「ViewTest/Edit」は2つあります。
1つ目の 「ViewTest/Edit」は、ビューを表示する際に呼び出されます。
このメソッドでは、指定されたidのレコードをAPI(api/ApiTest/{id})から取得し、ビューに渡して表示しています。
注意点としては、Editの引数を「Optional ByVal id As Integer = -1」としていることろです。
こうすることで、idを省略してもメソッドが呼び出せるようになります。
ただし、idが省略された場合そのまま処理するわけにはいかないので、「BadRequest」応答を返しています。
2つ目の 「ViewTest/Edit」 はHttpPost属性が付いており、ビューからPOSTがおこなわれた際に呼び出されます。
ビューで入力した情報をFormCollectionから取り出してRecordクラスを作成し、JsonConvertを使ってJsonに変換した後、HttpClientとHttpResponseMessageを使用してAPIにPUTリクエストをおこなっています。
コード
Imports System.Web.Mvc
Namespace Controllers
Public Class ViewTestController
Inherits Controller
' GET: ViewTest
Function Index() As ActionResult
Return View()
End Function
' GET: ViewTest/Details/5
Function Details(ByVal id As Integer) As ActionResult
Return View()
End Function
' GET: ViewTest/Create
Function Create() As ActionResult
'画面パラメータ作成
Dim model As New ViewTestParam
model.Item1 = New List(Of Record) From {New Record()}
model.Item2 = ""
Return View(model)
End Function
' POST: ViewTest/Create
<HttpPost()>
Function Create(ByVal collection As FormCollection) As ActionResult
' TODO: Add insert logic here
'レコード作成するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest"
'レコード作成
Dim rec As New Record
rec.col1 = collection("col1")
rec.col2 = collection("col2")
rec.col3 = New Date(2021, 1, 1)
'レコードをシリアル化
Dim json As String = ""
json = Newtonsoft.Json.JsonConvert.SerializeObject(rec)
'POST
Dim result As System.Net.Http.HttpResponseMessage
Dim clt As New Net.Http.HttpClient
Dim content As New Net.Http.StringContent(json, Encoding.UTF8, "application/json")
result = clt.PostAsync(url, content).Result
'画面パラメータ作成
Dim model As New ViewTestParam
model.Item1 = New List(Of Record)
model.Item1.Add(rec)
'メッセージを取り出し
model.Item2 = result.Content.ReadAsStringAsync.Result
Return View(model)
End Function
' GET: ViewTest/Edit/5
Function Edit(Optional ByVal id As Integer = -1) As ActionResult
'idが未指定の呼び出しの場合
If (id = -1) Then
Return New HttpStatusCodeResult(Net.HttpStatusCode.BadRequest)
End If
'id のレコードを取得するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest/" & id.ToString
'GETを実行
Dim clt As New Net.Http.HttpClient
Dim result As New System.Net.Http.HttpResponseMessage
result = clt.GetAsync(url).Result
Dim model As New ViewTestParam
Dim rec As Record
If (result.StatusCode = Net.HttpStatusCode.OK) Then
'Jsonを取り出し
Dim json As String
json = result.Content.ReadAsStringAsync.Result
'デシリアライズ
rec = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Record)(json)
'画面パラメータ作成
model.Item1 = New List(Of Record)
model.Item1.Add(rec)
model.Item2 = ""
Else
'画面パラメータ作成
model.Item1 = New List(Of Record) From {New Record()}
model.Item2 = ""
End If
Return View(model)
End Function
' POST: ViewTest/Edit/5
<HttpPost()>
Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult
' TODO: Add update logic here
'レコード作成するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest/" & id.ToString
'レコード作成
Dim rec As New Record
rec.col1 = collection("col1")
rec.col2 = collection("col2")
rec.col3 = New Date(2021, 1, 1)
'レコードをシリアル化
Dim typ As Type = rec.GetType
Dim dtslz As New Runtime.Serialization.Json.DataContractJsonSerializer(typ)
Dim json As String = ""
json = Newtonsoft.Json.JsonConvert.SerializeObject(rec)
'PUTを実行
Dim result As System.Net.Http.HttpResponseMessage
Dim clt As New Net.Http.HttpClient
Dim content As New Net.Http.StringContent(json, Encoding.UTF8, "application/json")
result = clt.PutAsync(url, content).Result
'画面パラメータ作成
Dim model As New ViewTestParam
model.Item1 = New List(Of Record)
model.Item1.Add(rec)
'メッセージを取り出し
model.Item2 = result.Content.ReadAsStringAsync.Result
Return View(model)
End Function
' GET: ViewTest/Delete/5
Function Delete(ByVal id As Integer) As ActionResult
Return View()
End Function
' POST: ViewTest/Delete/5
<HttpPost()>
Function Delete(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult
Try
' TODO: Add delete logic here
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function
End Class
End Namespace
ビュー(View)の追加
ビューを追加します。
ソリューションエクスプローラで、「Views」>「ViewTest」フォルダーを右クリックして
表示されるメニューから、「追加」>「ビュー」を選択します。
「MVC」>「表示」>「MVC5ビュー」を選択し、「追加」をクリックします。
ビュー名は「Edit」とし、テンプレートも「Edit」を選択します。
モデルクラスは「Record」を選択して、「追加」をクリックしてください。
「ViewTest」フォルダーに「Edit」という名前のビューが追加されます。
これで、「ViewTest/Edit」というビューと、それを処理する「ViewTestController」というコントローラーが用意できました。
ただ、このまま実行してもエラーになります。
追加したビュー(ViewTestのEdit.vbhtml)を変更して、パラメータを受け取れるようにします。
まずはMediaTypが「Record」になっているのを、「ViewTestParam」クラスに変更します。
メッセージ表示用に「message_label」というラベルを用意し、 「ViewTestParam」クラス の「Item2」の内容を赤文字で出力するようにします。
また、入力エリアは「ViewTestParam」クラス の「Item1」の内容を出力・検証するようにします。
コード
@ModelType ViewTestParam
@Code
ViewData("Title") = "Edit"
End Code
<h2>Edit</h2>
@*ViewTestControllerのEdit (Put) *@
@Using (Html.BeginForm("Edit", "ViewTest", FormMethod.Post))
@Html.AntiForgeryToken()
@<div class="form-horizontal">
<h4>Record</h4>
<hr />
@Html.Label("message_label", Model.Item2, New With {.style = "color:red;"})
<br />
@Html.ValidationSummary(True, "", New With {.class = "text-danger"})
<div class="form-group">
@Html.LabelFor(Function(model) model.Item1.First.col1, htmlAttributes:=New With {.class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Item1.First.col1, New With {.htmlAttributes = New With {.class = "form-control"}})
@Html.ValidationMessageFor(Function(model) model.Item1.First.col1, "", New With {.class = "text-danger"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(model) model.Item1.First.col2, htmlAttributes:=New With {.class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Item1.First.col2, New With {.htmlAttributes = New With {.class = "form-control"}})
@Html.ValidationMessageFor(Function(model) model.Item1.First.col2, "", New With {.class = "text-danger"})
</div>
</div>
@*使用しないのでコメントにする*@
@*
<div class="form-group">
@Html.LabelFor(Function(model) model.col3, htmlAttributes:=New With {.class = "control-label col-md-2"})
<div class="col-md-10">
@Html.LabelFor(Function(model) model.col3, New With {.htmlAttributes = New With {.class = "form-control"}})
@Html.ValidationMessageFor(Function(model) model.col3, "", New With {.class = "text-danger"})
</div>
</div>
*@
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
End Using
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@Section Scripts
@Scripts.Render("~/bundles/jqueryval")
End Section
実行して確認する
さっそく実行してみましょう。実行方法はこちらを参照してください。
まずは、id指定をせずに呼び出してみましょう。
アドレスバーに「/ViewTest/Edit」と入力してEnterキーを押してページを移動してみてください。
idが省略された場合はBadRequest応答をするようにしたので、 BadRequestと表示されます。
次は、idを指定して呼び出してみましょう。
アドレスバーに「/ViewTest/Edit/5」と入力してEnterキーを押してページを移動してみてください。
今度はEditページが表示されます。
col2を編集して「Save」ボタンをクリックします。
赤文字でメッセージが表示されたら、APIの呼び出し成功です。
出力ウィンドウも見てみましょう。
「ApiTestController」でリクエストの内容を取得できていることが確認できます。
─出力─────────────────────────
更新前の内容
col1:5
col2:old data
col3:2020/12/01 0:00:00
更新後の内容
col1:5
col2:This is a record update test.
col3:2021/01/01 0:00:00
────────────────────────────
ビューからPUTリクエストをおこない、APIで処理した結果をビューに表示させてみました。
今回のサンプルではリクエストの内容をコンソールに出力しただけですが、実際にはデータベースやファイルへの更新をおこなう処理を実装することになります。