[VB.NET] REST API⑫ ビューからWeb APIにDELETE(Controller実装・Viewの追加と実行)

2021年10月7日

WebAPIにDELETEリクエストをおこない、データ削除をおこなうビューを追加してみましょう。
※ VisualStudio2019
このサンプルでは、[VB.NET] REST API⑩ ビューからWeb APIにPOST#1で作成したコントローラー(ApiTestController・ViewTestController)とモデルクラス(Recordクラス・ViewTestParamクラス)を使用しています 。

コントローラーのDeleteメソッドを実装

まずは APIのコントローラー「ApiTestController」の「DeleteValue」メソッドを実装します。
本来はデータベースやファイルからレコードを削除する処理を書くことになりますが、
このサンプルでは、Viewからリクエスト > Controllerで処理 > Viewで結果を表示 という一連の流れを確認するだけにしたいので、レスポンスとして成功のメッセージを返すだけの、ダミー処理です。

コード(POSTとPUTのコードも含まれています)

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 Function DeleteValue(ByVal id As Integer) As System.Net.Http.HttpResponseMessage

            '削除処理(このサンプルはダミー処理)
            Debug.Print(String.Format("id:{0}", id))

            'レスポンスメッセージ作成
            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 deleted successfully !", Encoding.UTF8, "text/plain")
            ret.Content = content

            Return ret
        End Function
    End Class
End Namespace

続いてビューのコントローラー「ViewTestController」の「Delete」メソッドを実装します。
「ViewTest/Delete」は2つあります。

1つ目の 「ViewTest/Delete」は、ビューを表示する際に呼び出されます。
このメソッドでは、指定されたidのレコードをAPI(api/ApiTest/{id})から取得し、ビューに渡して表示しています。
注意点としては、Deleteの引数を「Optional ByVal id As Integer = -1」としていることろです。
こうすることで、idを省略してもメソッドが呼び出せるようになります。
ただし、idが省略された場合そのまま処理するわけにはいかないので、「BadRequest」応答を返しています。

2つ目の 「ViewTest/Delete」 はHttpPost属性が付いており、ビューからPOSTがおこなわれた際に呼び出されます。
今回のサンプルでは、idのみで削除します。コンテンツは設定していません。

コード(CreateとEditのコードも含まれています)

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(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/Delete/5
        <HttpPost()>
        Function Delete(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult
            ' TODO: Add delete logic here

            'レコード作成するAPIのURL
            Dim url As String
            url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest/" & id.ToString

            'DELETE
            Dim result As System.Net.Http.HttpResponseMessage
            Dim clt As New Net.Http.HttpClient

            result = clt.DeleteAsync(url).Result

            '画面パラメータ作成
            Dim model As New ViewTestParam
            model.Item1 = New List(Of Record) From {New Record()}

            'メッセージを取り出し
            model.Item2 = result.Content.ReadAsStringAsync.Result

            Return View(model)
        End Function
    End Class
End Namespace

ビュー(View)の追加

ビューを追加します。
ソリューションエクスプローラで、「Views」>「ViewTest」フォルダーを右クリックして
表示されるメニューから、「追加」>「ビュー」を選択します。

「MVC」>「表示」>「MVC5ビュー」を選択し、「追加」をクリックします。

ビュー名は「delete」とし、テンプレートも「Delete」を選択します。
モデルクラスは「Record」を選択して、「追加」をクリックしてください。

「ViewTest」フォルダーに「delete」という名前のビューが追加されます。
これで、「ViewTest/delete」というビューと、それを処理する「ViewTestController」というコントローラーが用意できました。
ただ、このまま実行してもエラーになります。

追加したビュー(ViewTestのdelete.vbhtml)を変更して、パラメータを受け取れるようにします。
まずはMediaTypが「Record」になっているのを、「ViewTestParam」クラスに変更します。
メッセージ表示用に「message_label」というラベルを用意し、 「ViewTestParam」クラス の「Item2」の内容を赤文字で出力するようにします。
また、表示エリアは「ViewTestParam」クラス の「Item1」の内容を出力・検証するようにします。

コード

@ModelType ViewTestParam
@Code
    ViewData("Title") = "delete"
End Code

<h2>delete</h2>

<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Record</h4>
    <hr />

    @Html.Label("message_label", Model.Item2, New With {.style = "color:red;"})
    <br />

    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(Function(model) model.Item1.First.col1)
        </dt>

        <dd>
            @Html.DisplayFor(Function(model) model.Item1.First.col1)
        </dd>

        <dt>
            @Html.DisplayNameFor(Function(model) model.Item1.First.col2)
        </dt>

        <dd>
            @Html.DisplayFor(Function(model) model.Item1.First.col2)
        </dd>

        <dt>
            @Html.DisplayNameFor(Function(model) model.Item1.First.col3)
        </dt>

        <dd>
            @Html.DisplayFor(Function(model) model.Item1.First.col3)
        </dd>

    </dl>
    @*ViewTestControllerのDelete (Post) *@
    @Using (Html.BeginForm("Delete", "ViewTest", FormMethod.Post))
        @Html.AntiForgeryToken()

        @<div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    End Using
</div>

実行して確認する

さっそく実行してみましょう。実行方法はこちらを参照してください。
まずは、id指定をせずに呼び出してみましょう。
アドレスバーに「/ViewTest/delete」と入力してEnterキーを押してページを移動してみてください。
idが省略された場合はBadRequest応答をするようにしたので、 BadRequestと表示されます。

次は、idを指定して呼び出してみましょう。
アドレスバーに「/ViewTest/delete/5」と入力してEnterキーを押してページを移動してみてください。
今度はdeleteページが表示されます。
「Delete」ボタンをクリックします。

赤文字でメッセージが表示されたら、APIの呼び出し成功です。

出力ウィンドウも見てみましょう。
「ApiTestController」でリクエストの内容を取得できていることが確認できます。

─出力─────────────────────────
id:5
────────────────────────────

ビューからDELETEリクエストをおこない、APIで処理した結果をビューに表示させてみました。
今回のサンプルではリクエストの内容をコンソールに出力しただけですが、実際にはデータベースやファイルへの更新をおこなう処理を実装することになります