【T10b】簡易ブログソフトウェアの作成 Part.Ⅳ ~ ファイルのアップロード/ダウンロード(3/7)
プロジェクトタイプ | (注意: 本文参照) |
---|---|
プロジェクト名 | T10b |
ソリューション名 | PIT10 |
注意
- 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
- 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
- プロジェクトの作成作業については準備作業を参照せよ.
10b-3. ファイルのアップロード/ダウンロード
ウェブアプリケーションではファイルのアップロードやダウンロードの機能が求められるものも少なくない. X(Twitter)やFacebookといった商用のサービスなどはもちろんのこと,昔ながらの画像掲示板やもちろんウェブログなどでも ファイルを扱う機能を備えているものは一般的である. ウェブアプリケーションでファイルを扱う場合,最も気にしなければならないのは アップロードされたファイルをどこに置くか である. これには以下のようなシナリオがありうる.
- データベース内に保存する.
- ファイルシステムに直接保存する.
- オブジェクトストレージを利用する.
1.はリレーショナルデータベース内にファイルを保存する方法である. リレーショナルデータベース製品の中には任意のバイトストリーム(=バイナリデータ)をテーブルの列の値として保存する機能を持つものは少なくない. 本コースで使用しているPostgreSQLの場合はbyteaという列の型があり, これを用いてファイルの内容をデータベースのテーブルに詰め込むことは可能である.可能であると書いたのは,このような方法は限定的な目的でしか採用しないのが 一般的であるためである.なぜならデータベース内にテーブルの列として巨大なファイルを保存してしまうと, パフォーマンスの低下につながる場合があるためである.
3.はAmazon S3やMicrosoft Azure Storage, 国内のサービスであればさくらのクラウドやConoHa VPSの オブジェクトストレージサービスのようなパブリックサービスを利用する方法である.こういったサービスは普通は有償だが, そのウェブアプリのデータ管理方法の1オプションとして提供するのは有用だろう.
本節では2.のウェブアプリを動作させているマシンのファイルシステムを直接利用する方法を学ぶことにする.
今回作成しているアプリケーションはウェブログということなので,「記事」に対して複数の「添付ファイル」を 関連付けて保存ができることにしよう.つまりデータモデルとしては_のようになる.
今回はファイルの本体はデータベースではなくファイルシステム内の適当なフォルダーに保存するが, プログラム上は「添付ファイル」が_に示したようなデータモデルとして認識される必要があるので, やはり今までと同様に「添付ファイル」に相当するモデルクラスを定義する必要がある. このモデルクラスには,アップロードされたファイルの メタ情報 (ファイル名,ファイルタイプなど)だけを格納することにする.
各「添付ファイル」のレコードに対応する ファイルの在り処 の管理については,ASP.NET Core はそのための機能を提供しないので アプリケーションが自ら責任を持つ必要がある.今回は単純に事前定義した保存フォルダー内に,アップロードされたファイルを 「添付ファイル」の主キーと同じ名前で保存するという戦略をとることにしよう.1つのフォルダ内に配置されるファイルの名前は 衝突(重複)が許されないが主キーは重複する恐れがないためこのような方法が可能である.
それではまずは「添付ファイル」に対応するモデルクラスを作成しよう.この「添付ファイル」の情報には _に示す項目を含めることにしよう.
項目名 | 必須/任意 | データ型 | 備考 |
---|---|---|---|
ID | 必須 | 整数 | 添付ファイルのID(主キー). |
ファイル名 | 必須 | 文字列 | 添付ファイルのファイル名. |
コンテントタイプ | 必須 | 文字列 | 添付ファイルのファイルタイプ(MIME). |
アップロード日時 | 必須 | 日付時刻 | 添付ファイルをアップロードした日時. |
この「添付ファイル」に対応するモデルクラスを定義しよう.クラス名はAttachmentとする.
まずプロジェクト内の Models フォルダを右クリックし,「追加」→「クラス」をクリックする.
作成するクラス名を訊かれるのでAttachment
(.csは省略可能)と入力して「追加」ボタンをクリックする.
すると空のクラス定義が作られるので_の定義を書き込もう.
|
|
この参照ナビゲーションプロパティに合わせてArticle
クラスにもコレクションナビゲーションプロパティを追加しておこう.
Models/Article.cs に_に示す内容を追記する.
|
|
Attachment
クラスがデータベース側に反映されるようにするには,データコンテキストクラスにも手を加える必要がある.
Data/T10bContext.cs に_に示す内容を追記しよう.
|
|
ここまで追記ができたらコマンドラインターミナル1で_に示すコマンドを 用いてマイグレーションコードの生成とデータベース側への適用を行おう.
PS>
dotnet ef migrations add AddAttachmentPS>
dotnet ef database update
アップロードされたファイルの保存場所については,前節と同様に決め打ちではなく設定ファイルで設定可能にしておこう. appsettings.json および SiteSettings.cs にそれぞれ_,_に示す内容を追記する.
|
|
|
|
「添付ファイル」の操作のためのアクションに関しては,専用のコントローラーを作成するのではなく,
Articles
コントローラーに組み込むことにする.このために,添付ファイルのアップロード,取得,削除のための
3つのアクションUploadAttachment
,GetAttachment
,DeleteAttachment
を追加する.
これらの画面イメージと画面遷移を_に示す.
なお,この図では,図9b-3-1,図9b-3-2で
提示済みの画面遷移の矢印は省略している.
ファイルの添付は記事編集画面(Edit
)からのみ辿ることができるようにしておく.これは記事の新規作成時は
添付ファイルの作成が行えないことも意味するが,新規作成時にも添付ファイルを追加できるような設計にすること
自体はそれほど難しくない.ここでは簡単のためいったん保存済みに記事に対してしか添付ファイルの作成を行えないようにしている.
UploadAttachment
アクションはファイルのアップロードを担うアクションである.このアクションはフォームの表示と,フォームからの送信の
双方を行う必要があるためGET用とPOST用の両方を用意する必要がある.
GetAttachment
は添付されたファイルを取得するためのアクションである.このアクションは基本的にGET用のみであるが,ビューは持たず
ファイルの内容そのものをレスポンスとしてクライアントに返送する.
このアクションに限り匿名ユーザー,つまりは一般の閲覧者にもアクセス可能にしておく.
DeleteAttachment
は添付ファイルの削除のためのアクションである.
また,これらに合わせて記事の個別表示画面(Details
)および記事編集画面(Edit
)にも添付ファイルの一覧が表示されるようにしておく.
アプリケーションでファイルをアップロードするには以下のようにする.
- IFormFileインターフェース型のプロパティをもつモデルクラスを定義する.
- ↑のモデルクラスを @model ディレクティブに指定したビューを作成する.
- form 要素の enctype 属性に
multipart/form-data
を指定する. - フォームの input 要素に asp-for タグヘルパーを使って↑のプロパティを関連付ける.
まず1.のためのモデルクラスを用意しよう.プロジェクト内の Models フォルダを右クリックし,「追加」→「クラス」をクリックする.
作成するクラス名を訊かれるのでUploadFile
(.csは省略可能)と入力して「追加」ボタンをクリックする.
すると空のクラス定義が作られるので_の定義を書き込もう.
|
|
つぎにUploadAttachment
アクションとそのためのビューを作成しよう.
このために以降の処理で必要となるいくつかの小道具を追加しておこう.
Articles
コントローラーに_に示す内容を追記しよう.
ファイルの冒頭に_に示すusingディレクティブを追記する必要がある点に注意しよう.
|
|
|
|
_では private なUploadFileFolder
プロパティ(読み取り専用)と,
GetAttachmentFilePath()
メソッドを定義している.
UploadFileFolder
プロパティは設定ファイルから,アップロードされたファイルの保存先のフォルダの場所を
取得して,絶対パスに変換して返すプロパティである.これは例えば以下のように解釈される.
- 例) appsettings.json の
UploadFileFolder
の設定値 "Attachments"
- 例) プログラムの実行体の場所
"C:\Users\Hoge\source\repo\WebApp\bin\Release\WebApp.dll"
- 添付ファイルの保存先
"C:\Users\Hoge\source\repo\WebApp\bin\Release\Attachments\"
また,このプロパティはこの保存フォルダが存在していなければ作成する,という作用も持っている.
GetAttachmentFilePath()
メソッドは,引き数として渡された_のAttachment
クラスのインスタンスに対応する
ファイルパスを取得するメソッドである.このパスはコメントに書いてあるように
という形式のパスとなる.これは例えば以下のような解釈を行い,メソッドの戻り値としては 拡張子なしのファイルパス を返してくる.保存フォルダー
\添付ファイルID
- 例)
保存フォルダー
(=前述の「添付ファイルの保存先」) "C:\Users\Hoge\source\repo\WebApp\bin\Release\Attachments\"
- 例)
添付ファイルID
72
GetAttachmentFilePath()
メソッドの戻り値"C:\Users\Hoge\source\repo\WebApp\bin\Release\Attachments\72"
タブのタイトルは「開発用PowerShell」もしくは「Developer PowerShell」となっている. ↩︎