[VB.NET] REST API⑬ ビューからWeb APIにファイルをアップロード
ビューからWeb APIにファイルをアップロードしてみましょう。
※ VisualStudio2019
APIプロジェクトの作成方法 についてはこちらを参照してください。
API用のコントローラーを追加
まずはAPI用のコントローラを追加します。
ソリューションエクスプローラで、「Controllers」を右クリックして表示されるメニューから、
「追加」>「コントローラー」を選択します。
このサンプルでは、空のコントローラーを使います。
「WebAPI」から、「Web API 2 コントローラー 空」を選択し、「追加」をクリックします。
コントローラーの名前を入力して、「追加」をクリックします。
名前は必ず「***Controller」としてください。 ※「***」の部分は任意です。
この例では、「ApiTestController 」としています 。
コントローラーに ファイルアップロード用のPOSTメソッドを実装
追加したコントローラー「ApiTestController 」にファイルアップロード用のPOSTメソッドを実装しましょう。
このサンプルでは「PostFileStream」というメソッド名にしました。
「HttpPost」と「ActionName(“PostFileStream")」という属性をメソッドに付けている点に注意してください。
後ほど、このメソッドを呼び出せるように WebApiConfig.vb にルートをマップするコードを追加します。
※メソッド名は「PostValue」でも構いません。その場合はWebApiConfig.vbの ルート追加はしなくてもよいです。
「PostFileStream」 メソッドでは、受け取ったファイルデータ(Stream)を「App_Data」に保存しています。
ファイルデータはStreamContentから一度MemoryStreamに読み出し、それをFileStreamにコピーして保存しています。
※直接FileStreamに読ませたかったのですが・・・うまくいきませんでした。出来ないのか、調べ方が悪いのか。
最後に、ビューに表示させたいメッセージを応答しています。
このメッセージがビューに表示され、アップロードしたファイルが保存できれば目的達成です。
コード
Imports System.Net
Imports System.Web.Http
Namespace Controllers
Public Class ApiTestController
Inherits ApiController
' POST: api/ApiTest/PostFileStream
<HttpPost>
<ActionName("PostFileStream")>
Public Function PostFileStream(ByVal value As System.Net.Http.HttpRequestMessage) As System.Net.Http.HttpResponseMessage
'保存先のファイルパス(App_Data)
Dim path As String
path = HttpContext.Current.Server.MapPath("~/App_Data/" & value.Content.Headers.ContentDisposition.FileName)
Using mem As New System.IO.MemoryStream()
'読み出し
mem.Position = 0
value.Content.ReadAsStreamAsync.Result.CopyTo(mem)
'ファイルを保存
Using sr As New System.IO.FileStream(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)
mem.Position = 0
mem.CopyTo(sr)
End Using
End Using
'レスポンスメッセージ作成
Dim ret As System.Net.Http.HttpResponseMessage
ret = New System.Net.Http.HttpResponseMessage(HttpStatusCode.OK)
'成功メッセージを設定
Dim content As New Net.Http.StringContent("The file was saved successfully !", Encoding.UTF8, "text/plain")
ret.Content = content
Return ret
End Function
End Class
End Namespace
次に、「App_Start」>「WebApiConfig.vb」のコードを開きます。
ここに、「 PostFileStream 」メソッドをマップするためのコードを追加します。
コード
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web.Http
Public Module WebApiConfig
Public Sub Register(ByVal config As HttpConfiguration)
' Web API の設定およびサービス
'jsonをブラウザで表示させる
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(New System.Net.Http.Headers.MediaTypeHeaderValue("text/html"))
' Web API ルート
config.MapHttpAttributeRoutes()
'ファイルアップロード用のAPI
config.Routes.MapHttpRoute(
name:="CustomApi",
routeTemplate:="api/{controller}/{action}",
defaults:=New With {.id = RouteParameter.Optional}
)
config.Routes.MapHttpRoute(
name:="DefaultApi",
routeTemplate:="api/{controller}/{id}",
defaults:=New With {.id = RouteParameter.Optional}
)
End Sub
End Module
ビュー用のコントローラーを追加
続いてビュー用のコントローラを追加します。
ソリューションエクスプローラで、「Controllers」を右クリックして表示されるメニューから、
「追加」>「コントローラー」を選択します。
今度は「MVC」>「コントローラー」から、
「MVC 5 コントローラー 空」を選択し、「追加」をクリックします。
コントローラーの名前を入力して、「追加」をクリックします。
こちらも名前は必ず「***Controller」としてください。 ※「***」の部分は任意です。
この例では、「ViewTestController 」としています。
ビューのコントローラー「ViewTestController」に「upload」メソッドを実装します。
「ViewTest/upload」はメソッドを2つ用意します。
1つ目の 「ViewTest/upload」は、ビューを表示する際に呼び出されます。
このメソッドでは、メッセージ表示用のViewDataを初期化しています。
2つ目の 「ViewTest/upload」 はHttpPost属性が付いており、ビューからPOSTがおこなわれた際に呼び出されます。
ビューで選択したファイル情報をHttpPostedFileBaseから取り出してStreamContentを作成し、HttpClientとHttpResponseMessageを使用してAPIにPOSTリクエストをおこなっています。
コード
Imports System.Web.Mvc
Namespace Controllers
Public Class ViewTestController
Inherits Controller
Function upload() As ActionResult
ViewData("msg") = ""
Return View()
End Function
<HttpPost()>
<ValidateAntiForgeryToken>
Function upload(ByVal post_file As HttpPostedFileBase) As ActionResult
If (IsNothing(post_file)) Then
ViewData("msg") = "ファイルを指定してください!"
Else
'レコード作成するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest/PostFileStream"
'POST
Dim result As System.Net.Http.HttpResponseMessage
Dim clt As New Net.Http.HttpClient
Dim content As Net.Http.StreamContent
'ストリームコンテンツ
content = New Net.Http.StreamContent(post_file.InputStream)
'コンテンツタイプ
content.Headers.ContentDisposition = New System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
content.Headers.ContentType = New System.Net.Http.Headers.MediaTypeHeaderValue(post_file.ContentType)
'ファイル名
content.Headers.ContentDisposition.FileName = post_file.FileName
'アップロード実行
result = clt.PostAsync(url, content).Result
Dim model As New ViewTestParam With {.Item1 = ""}
'メッセージを取り出し
ViewData("msg") = String.Format("{0} ({1})", result.Content.ReadAsStringAsync.Result, post_file.FileName)
End If
Return View()
End Function
End Class
End Namespace
ビュー(View)の追加
ビューを配置する フォルダー を用意します。
ソリューションエクスプローラで、「Views」フォルダーを右クリックして表示されるメニューから、
「追加」>「新しいフォルダー」を選択します。
作成したフォルダーの名前は「ViewTest」にします。
ビューを追加します。
ソリューションエクスプローラで、作成したばかりの「ViewTest」フォルダーを右クリックして
表示されるメニューから、「追加」>「ビュー」を選択します。
「MVC」>「表示」>「MVC5ビュー」を選択し、「追加」をクリックします。
ビュー名は「upload」とし、テンプレートは「Empty(モデルなし)」を選択して、「追加」をクリックします。
「ViewTest」フォルダーに「upload」という名前のビューが追加されます。
これで、「ViewTest/upload」というビューと、それを処理する「ViewTestController」というコントローラーが用意できました。
追加した「upload」ビューにファイルをアップロードするためのコードを書き加えます。
「input type="file"」でファイル選択のダイアログを表示して、ファイルを選択できるようにします。
この時、「name="post_file“」としている点に注意してください。
今回のサンプルでは、ビューのコントローラー「ViewTestController」の「upload」メソッドを実装した時に、
… Function upload(ByVal post_file As HttpPostedFileBase) As ActionResult
と、メソッドの引数を「 post_file 」という名前にしています。
この引数名とinputのnameを一致させることで、選択されたファイルの情報「upload」メソッドに渡すことができます。
コード
@Code
ViewData("Title") = "upload"
End Code
<h2>upload</h2>
@Html.Label("message_label", ViewData("msg").ToString, New With {.style = "color:red;"})
<div>
@Using (Html.BeginForm("upload", "ViewTest", FormMethod.Post, New With {.enctype = "multipart/form-data"}))
@Html.AntiForgeryToken()
@<input type="file" name="post_file" />
@<input type="submit" value="アップロード" />
End Using
</div>
実行して確認する
さっそく実行してみましょう。実行方法はこちらを参照してください。
アドレスバーに「/ViewTest/upload」と入力してEnterキーを押してページを移動してください。
アップロードページが表示されたら、「ファイルを選択」でファイルを選びます。
このサンプルでは、「up_test.csv」というCSVファイルをアップロードしてみます。
※アップロードのテストに使うだけですので、ファイルはCSVでなくても構いません。
ファイルを選択したら、「アップロード」をクリックします。
赤文字でメッセージが表示されたら、APIの呼び出しは成功です。
ファイルもしっかり「App_Data」フォルダに保存されています。
ビューからPOSTリクエストをおこない、Web APIにファイルをアップロードしてみました。
今回のサンプルではWeb APIの「App_Data」フォルダにアップロードしたファイルを保存していますが、
実際にはファイルを格納するサーバーやフォルダを用意して、そこに保存するのが良いと思います。
また、今回はなんとなく気分で「StreamContent」を使っていますが、「ByteArrayContent」を使っても実現可能です。