ファイルのアップロード (C#)

作成者: Scott Mitchell

PDF のダウンロード

ユーザーがバイナリ ファイル (Word や PDF ドキュメントなど) を Web サイトにアップロードし、サーバーのファイル システムまたはデータベースに保存できるようにする方法について学習します。

はじめに

これまでに調べたすべてのチュートリアルでは、テキスト データのみを操作してきました。 しかし、多くのアプリケーションには、テキスト データとバイナリ データの両方をキャプチャするデータ モデルがあります。 オンライン出会い系サイトでは、ユーザーが自分のプロファイルに関連付ける写真をアップロードできる場合があります。 求人 Web サイトでは、ユーザーが履歴書を Microsoft Word または PDF ドキュメントとしてアップロードできる場合があります。

バイナリ データを操作する場合、さらに新たな一連の課題が発生します。 バイナリ データをアプリケーションに保存する方法を決定する必要があります。 新しいレコードの挿入に使用されるインターフェイスは、ユーザーが自分のコンピューターからファイルをアップロードできるように更新する必要があります。また、レコードの関連付けられているバイナリ データをダウンロードするための手段を表示または提供するための追加の手順を行う必要があります。 このチュートリアルと次の 3 つのチュートリアルでは、これらの課題を乗り越える方法について調べます。 これらのチュートリアルの最後に、写真と PDF パンフレットを各カテゴリに関連付ける完全に機能するアプリケーションを構築することになります。 この特定のチュートリアルでは、バイナリ データを保存するためのさまざまな手法を確認し、ユーザーが自分のコンピューターからファイルをアップロードし、Web サーバーのファイル システムに保存できるようにする方法について調べます。

Note

アプリケーションのデータ モデルの一部であるバイナリ データは、Binary Large OBject の頭字語である BLOB と呼ばれることもあります。 これらのチュートリアルでは、BLOB という用語は同義ですが、バイナリ データという用語を使用することにしました。

手順 1: バイナリ データの操作 Web ページの作成

バイナリ データのサポートの追加に関する課題を調べ始める前に、まず、少し時間を取って、このチュートリアルと次の 3 つチュートリアルのために必要な ASP.NET ページを Web サイト プロジェクトに作成してみましょう。 まず、BinaryData という名前の新しいフォルダーを追加します。 次に、次の ASP.NET ページをそのフォルダーに追加し、各ページを Site.master マスター ページに関連付けます。

  • Default.aspx
  • FileUpload.aspx
  • DisplayOrDownloadData.aspx
  • UploadInDetailsView.aspx
  • UpdatingAndDeleting.aspx

バイナリ データ関連のチュートリアルの ASP.NET ページを追加する

図 1: バイナリ データ関連のチュートリアルの ASP.NET ページを追加する

他のフォルダーと同様に、BinaryData フォルダーの Default.aspx のセクションにチュートリアルが一覧表示されます。 SectionLevelTutorialListing.ascx ユーザー コントロールではこの機能が提供されていることを思い出してください。 そのため、このユーザー コントロールをソリューション エクスプローラーからページのデザイン ビューにドラッグして Default.aspx に追加します。

SectionLevelTutorialListing.ascx ユーザー コントロールを Default.aspx に追加する

図 2: SectionLevelTutorialListing.ascx ユーザー コントロールを Default.aspx に追加する (クリックするとフルサイズの画像を表示されます)

最後に、これらのページをエントリとして Web.sitemap ファイルに追加します。 具体的には、GridView の拡張 <siteMapNode> の後に次のマークアップを追加します。

<siteMapNode 
    title="Working with Binary Data" 
    url="~/BinaryData/Default.aspx" 
    description="Extend the data model to include collecting binary data.">
    
    <siteMapNode 
        title="Uploading Files" 
        url="~/BinaryData/FileUpload.aspx" 
        description="Examine the different ways to store binary data on the 
                     web server and see how to accept uploaded files from users 
                     with the FileUpload control." />
    <siteMapNode 
        title="Display or Download Binary Data" 
        url="~/BinaryData/DisplayOrDownloadData.aspx" 
        description="Let users view or download the captured binary data." />
    <siteMapNode 
        title="Adding New Binary Data" 
        url="~/BinaryData/UploadInDetailsView.aspx" 
        description="Learn how to augment the inserting interface to 
                     include a FileUpload control." />
    <siteMapNode 
        title="Updating and Deleting Existing Binary Data" 
        url="~/BinaryData/UpdatingAndDeleting.aspx" 
        description="Learn how to update and delete existing binary data." />
</siteMapNode>

Web.sitemap を更新した後、少し時間を取って、ブラウザーを介してチュートリアル Web サイトを表示します。 左側のメニューに、バイナリ データの操作に関するチュートリアルの項目が含まれるようになりました。

サイト マップに、バイナリ データの操作に関するチュートリアルのエントリが含まれるようになりました

図 3: サイト マップに、バイナリ データの操作に関するチュートリアルのエントリが含まれるようになった

手順 2: バイナリ データを保存する場所の決定

アプリケーションのデータ モデルに関連付けられているバイナリ データは、2 つの場所のいずれか (データベースに保存されているファイルへの参照を持つ Web サーバーのファイル システム上、またはデータベース自体内に直接) に保存できます (図 4 を参照)。 各方法には独自の一連の長所と短所があり、より詳細な議論を行う価値があります。

バイナリ データは、ファイル システムに格納することも、データベースに直接格納することもできます

図 4: バイナリ データはファイル システムまたはデータベースに直接保存できる (クリックするとフルサイズの画像が表示されます)

Northwind データベースを拡張して、写真を各製品に関連付ける必要があるとします。 1 つのオプションは、Web サーバーのファイル システムにこれらの画像ファイルを保存し、Products テーブルにパスを記録することです。 この方法では、おそらく、varchar(200) 型の Products テーブルに ImagePath 列を追加します。 ユーザーがチャイの写真をアップロードすると、その写真は Web サーバーのファイル システム (~/Images/Tea.jpg) に保存される可能性があります。ここで、~ はアプリケーションの物理パスを表します。 つまり、Web サイトが物理パス C:\Websites\Northwind\ でルート化されている場合、~/Images/Tea.jpgC:\Websites\Northwind\Images\Tea.jpg と同等になります。 画像ファイルをアップロードした後、Products テーブルのチャイ レコードを更新して、ImagePath 列で新しい画像のパスが参照されるようにします。 すべての製品画像をアプリケーションの Images フォルダーに配置することにした場合、~/Images/Tea.jpg または単に Tea.jpg を使用することができます。

バイナリ データをファイル システムに保存する主な利点は次のとおりです。

  • 実装が簡単: 後で簡単に説明しますが、データベース内に直接バイナリ データを保存したり、それを取得するには、ファイル システムを介してデータを操作する場合よりも少し多くのコードが必要になります。 さらに、ユーザーがバイナリ データを表示またはダウンロードするには、そのデータの URL を表示する必要があります。 データが Web サーバーのファイル システムに存在する場合、URL は簡単です。 ただし、データがデータベースに保存されている場合は、データベースからデータを取得して返す Web ページを作成する必要があります。
  • バイナリ データへのより広範なアクセス: データベースからデータをプルできない他のサービスまたはアプリケーションからバイナリ データにアクセスできる必要がある場合があります。 たとえば、各製品に関連付けられている画像を FTP 経由でユーザーが使用できるようにする必要がある場合もあります。その場合は、バイナリ データをファイル システムに保存する必要があります。
  • パフォーマンス: バイナリ データがファイル システムに保存されている場合、バイナリ データがデータベース内に直接保存されている場合よりも、データベース サーバーと Web サーバー間の需要とネットワークの輻輳が少なくなります。

ファイル システムにバイナリ データを保存する場合の主な欠点は、データをデータベースから切り離すことです。 レコードが Products テーブルから削除された場合、Web サーバーのファイル システム上の関連付けられているファイルは自動的に削除されません。 ファイルを削除するために追加のコードを記述する必要があります。そうしないと、ファイル システムが未使用の孤立したファイルで乱雑になります。 さらに、データベースをバックアップする場合は、ファイル システム上の関連するバイナリ データのバックアップも必ず行う必要があります。 データベースを別のサイトまたはサーバーに移動すると、同様の課題が発生します。

バイナリ データは、varbinary 型の列を作成することで、Microsoft SQL Server 2005 データベースに直接保存することもできます。 他の可変長データ型と同様に、この列に保持できるバイナリ データの最大長を指定できます。 たとえば、最大 5,000 バイトを予約するには、varbinary(5000) を使用します。varbinary(MAX) では、最大ストレージ サイズ (約 2 GB) を使用できます。

バイナリ データをデータベースに直接保存する主な利点は、バイナリ データとデータベース レコードの間の密結合です。 これにより、バックアップや別のサイトまたはサーバーへのデータベースの移動など、データベース管理タスクが大幅に簡略化されます。 また、レコードを削除すると、対応するバイナリ データが自動的に削除されます。 また、バイナリ データをデータベースに保存することにはさらに小さな利点があります。 詳細については、「ASP.NET 2.0 を使用してデータベースにバイナリ ファイルを直接保存する」を参照してください。

Note

Microsoft SQL Server 2000 以前のバージョンでは、varbinary データ型の上限は 8,000 バイトでした。 最大 2 GB のバイナリ データを保存するには、代わりに image データ型 を使用する必要があります。 しかし、SQL Server 2005 での MAX の追加により、image データ型は非推奨となりました。 下位互換性のためにはまだサポートされていますが、Microsoft は、image データ型が将来のバージョンの SQL Server で削除されることを発表しました。

より古いデータ モデルを操作している場合、image データ型である可能性があります。 Northwind データベースの Categories テーブルには、カテゴリの画像ファイルのバイナリ データを保存するために使用できる Picture 列があります。 Northwind データベースのルートは Microsoft Access と以前のバージョンの SQL Server にあるため、この列は image 型です。

このチュートリアルと次の 3 つのチュートリアルでは、両方の方法を使用します。 Categories テーブルには、カテゴリの画像のバイナリ コンテンツを保存するための Picture 列が既に含まれています。 さらに列 (BrochurePath) を追加して、PDF へのパスを Web サーバーのファイル システムに保存します。これを使用して、カテゴリの印刷品質の洗練された概要を提供できます。

手順 3: Categories テーブルへの BrochurePath 列の追加

現在、Categories テーブルには、CategoryIDCategoryNameDescription、および Picture の 4 つの列しかありません。 これらのフィールドに加えて、カテゴリのパンフレット (存在する場合) を指す新しいものを追加する必要があります。 この列を追加するには、サーバー エクスプローラーに移動し、Tables をドリルダウンし、Categories テーブルを右クリックして、[テーブル定義を開く] を選択します (図 5 を参照)。 サーバー エクスプローラーが表示されない場合は、[表示] メニューから [サーバー エクスプローラー] オプションを選択して表示するか、Ctrl + Alt + S キーを押します。

BrochurePath という名前の、NULL を許可する、新しい varchar(200) 列を Categories テーブルに追加し、[保存] アイコンをクリックします (または Ctrl + S キーを押します)。

Categories テーブルに BrochurePath 列を追加する

図 5: Categories テーブルに BrochurePath 列を追加する (クリックするとフルサイズの画像が表示されます)

手順 4: PictureBrochurePath 列を使用するためのアーキテクチャの更新

現在、データ アクセス層 (DAL) の CategoriesDataTable には、CategoryIDCategoryNameDescriptionNumberOfProducts の 4 つの DataColumn が定義されています。 「データ アクセス層を作成する」チュートリアルでこの DataTable を最初に設計したときは、CategoriesDataTable には最初の 3 つの列しかありませんでした。NumberOfProducts 列は、「マスター レコードの箇条書きと詳細 DataList を使用してマスター/詳細を表示する」チュートリアルで追加されました。

データ アクセス層を作成する」で説明したように、型指定された DataSet の DataTable によってビジネス オブジェクトが構成されます。 TableAdapter には、データベースと通信し、ビジネス オブジェクトにクエリ結果を設定する役割があります。 CategoriesDataTable は、次の 3 つのデータ取得メソッドがある CategoriesTableAdapter によって設定されます。

  • GetCategories() では、TableAdapter のメイン クエリが実行され、Categories テーブル内のすべてのレコードの CategoryIDCategoryName、および Description フィールドが返されます。 メイン クエリは、自動生成された Insert および Update メソッドで使用されるものです。
  • GetCategoryByCategoryID(categoryID) では、CategoryIDcategoryID と等しいカテゴリの CategoryIDCategoryName、および Description フィールドが返されます。
  • GetCategoriesAndNumberOfProducts() - Categories テーブルのすべてのレコードの CategoryIDCategoryName、および Description フィールドを返します。 また、サブクエリを使用して、各カテゴリに関連付けられている製品の数を返します。

これらのクエリのいずれも、Categories テーブルの PictureBrochurePath 列を返さないことに注目してください。また、CategoriesDataTable ではこれらのフィールドに DataColumn が提供されません。 Picture および BrochurePath プロパティを操作するには、最初にそれらを CategoriesDataTable に追加してから、これらの列を返すように CategoriesTableAdapter クラスを更新する必要があります。

PictureBrochurePath``DataColumn の追加

まず、これら 2 つの列を CategoriesDataTable に追加します。 CategoriesDataTable のヘッダーを右クリックし、コンテキスト メニューから [追加] を選択し、[列] オプションを選びます。 これにより、Column1 という名前の新しい DataColumn が DataTable に作成されます。 この列の名前を Picture に変更します。 プロパティ ウィンドウで、DataColumnDataType プロパティを System.Byte[] に設定します (これはドロップダウン リストのオプションではありません。入力する必要があります)。

DataType が System.Byte[] である DataColumn 名前付き図を作成する

図 6: DataTypeSystem.Byte[]Picture という名前の DataColumn を作成する (クリックするとフルサイズの画像が表示されます)

DataTable にもう 1 つ DataColumn を追加し、既定の DataType 値 (System.String) を使用して BrochurePath という名前を付けます。

TableAdapter から PictureBrochurePath の値を返す

これら 2 つの DataColumnCategoriesDataTable に追加されたので、CategoriesTableAdapter を更新する準備ができました。 これらの両方の列値をメインの TableAdapter クエリで返すこともできますが、これにより、GetCategories() メソッドが呼び出されるたびにバイナリ データが戻ります。 代わりに、メインの tableAdapter クエリを更新して BrochurePath を戻し、特定のカテゴリの Picture 列を返す追加のデータ取得メソッドを作成しましょう。

メインの TableAdapter クエリを更新するには、CategoriesTableAdapter のヘッダーを右クリックし、コンテキスト メニューから [構成] オプションを選択します。 これにより、TableAdapter 構成ウィザードが起動します。これは、過去の多くのチュートリアルで見てきたものです。 クエリを更新して BrochurePath を戻し、[完了] をクリックします。

SELECT ステートメントの列リストを更新して、BrochurePath も返すようにする

図 7: SELECT ステートメントの列リストを更新して、BrochurePath も返すようにする (クリックするとフルサイズの画像が表示されます)

TableAdapter にアドホック SQL ステートメントを使用するときに、メイン クエリの列リストを更新すると、TableAdapter のすべての SELECT クエリ メソッドの列リストが更新されます。 つまり、GetCategoryByCategoryID(categoryID) メソッドが更新され、BrochurePath 列が返されます。これは、意図したとおりである可能性があります。 しかし、GetCategoriesAndNumberOfProducts() メソッドの列リストも更新され、各カテゴリの製品数を返すサブクエリが削除されました。 したがって、このメソッドの SELECT クエリを更新する必要があります。 GetCategoriesAndNumberOfProducts() メソッドを右クリックし、[構成] を選択し、SELECT クエリを元の値に戻します。

SELECT CategoryID, CategoryName, Description, 
       (SELECT COUNT(*) 
            FROM Products p 
            WHERE p.CategoryID = c.CategoryID) 
       as NumberOfProducts
FROM Categories c

次に、特定のカテゴリの Picture 列値を返す新しい TableAdapter メソッドを作成します。 CategoriesTableAdapter のヘッダーを右クリックし、[クエリの追加] オプションを選択して TableAdapter クエリ構成ウィザードを起動します。 このウィザードの最初の手順では、アドホック SQL ステートメント、新しいストアド プロシージャ、または既存のものを使用してデータのクエリを実行するかどうかが確認されます。 [SQL ステートメントを使用する] を選択して、[次へ] をクリックします。 行を返すので、2 番目の手順では [行を返す SELECT] オプションを選択します。

[SQL ステートメントの使用] オプションを選択する

図 8: [SQL ステートメントを使用する] オプションを選択する (クリックするとフルサイズの画像が表示されます)

クエリはカテゴリ テーブルからレコードを返すので、行を返す SELECT を選択します

図 9: クエリで Categories テーブルからレコードが返されるので、[行を返す SELECT] を選択する (クリックするとフルサイズの画像が表示されます)

3 番目の手順では、次の SQL クエリを入力し、[次へ] をクリックします。

SELECT     CategoryID, CategoryName, Description, BrochurePath, Picture
FROM       Categories
WHERE      CategoryID = @CategoryID

最後の手順では、新しいメソッドの名前を選択します。 DataTable を塗りつぶすパターンと GetCategoryWithBinaryDataByCategoryID DataTable パターンを返す場合は、 と をそれぞれ使用FillCategoryWithBinaryDataByCategoryIDします。 [完了] をクリックして、ウィザードを完了します。

TableAdapter メソッドの名前を選択する

図 10: TableAdapter のメソッドの名前を選択する (クリックするとフルサイズの画像を表示されます)

Note

TableAdapter クエリ構成ウィザードを完了すると、新しいコマンド テキストがメイン クエリのスキーマとは異なるスキーマのデータを返すことを知らせるダイアログ ボックスが表示される場合があります。 つまり、TableAdapter のメイン クエリ GetCategories() では、先ほど作成したものとは異なるスキーマが返されることがウィザードに示されます。 しかし、これは望んだことなので、このメッセージは無視してかまいません。

また、アドホック SQL ステートメントを使用していて、ウィザードを使って後で TableAdapter のメイン クエリを変更する場合は、メイン クエリの列だけを含むように GetCategoryWithBinaryDataByCategoryID メソッドの SELECT ステートメントの列リストが変更されることに注意してください (つまり、Picture 列がクエリから削除されます)。 この手順の前の GetCategoriesAndNumberOfProducts() メソッドの場合と同様に、Picture 列を返すように列リストを手動で更新する必要があります。

2 つの DataColumnCategoriesDataTable に追加し、GetCategoryWithBinaryDataByCategoryID メソッドを CategoriesTableAdapter に追加した後、型指定された DataSet デザイナーのこれらのクラスは、図 11 のスクリーンショットのようになるはずです。

DataSet デザイナーに新しい列とメソッドが含まれている

図 11: DataSet デザイナーに新しい列とメソッドが含まれている

ビジネス ロジック層 (BLL) の更新

DAL が更新されたので、あとは、新しい CategoriesTableAdapter メソッドのメソッドを含むようにビジネス ロジック層 (BLL) を拡張するだけです。 次のメソッドを CategoriesBLL クラスに追加します:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)] 
public Northwind.CategoriesDataTable 
    GetCategoryWithBinaryDataByCategoryID(int categoryID)
{
    return Adapter.GetCategoryWithBinaryDataByCategoryID(categoryID);
}

手順 5: クライアントから Web サーバーへのファイルのアップロード

バイナリ データを収集するときは、多くの場合、このデータはエンド ユーザーによって提供されます。 この情報をキャプチャするには、ユーザーが自分のコンピューターから Web サーバーにファイルをアップロードできる必要があります。 その後、アップロードされたデータをデータ モデルと統合する必要があります。これは、ファイルを Web サーバーのファイル システムに保存し、データベース内のファイルへのパスを追加することや、バイナリ コンテンツをデータベースに直接書き込むことを意味する場合があります。 この手順では、ユーザーが自分のコンピューターからサーバーにファイルをアップロードできるようにする方法を見ていきます。 次のチュートリアルでは、アップロードされたファイルとデータ モデルの統合に注目します。

ASP.NET 2.0 の新しい FileUpload Web コントロールでは、ユーザーが自分のコンピューターから Web サーバーにファイルを送信するためのメカニズムが提供されます。 FileUpload コントロールは、type 属性が file に設定されている <input> 要素としてレンダリングされ、ブラウザーは [参照] ボタンを含むテキスト ボックスとして表示されます。 [参照] ボタンをクリックすると、ユーザーがファイルを選択できるダイアログ ボックスが表示されます。 フォームがポストバックされると、選択されたファイルの内容がポストバックと共に送信されます。 サーバー側では、アップロードされたファイルに関する情報に、FileUpload コントロールのプロパティを使用してアクセスできます。

ファイルのアップロードを示すには、BinaryData フォルダーの FileUpload.aspx ページを開き、ツールボックスからデザイナーに FileUpload コントロールをドラッグし、コントロールの ID プロパティを UploadTest に設定します。 次に、IDText プロパティをそれぞれ UploadButton と選択したファイルのアップロードに設定して、Button Web コントロールを追加します。 最後に、Button の下に Label Web コントロールを配置し、その Text プロパティをクリアし、その ID プロパティを UploadDetails に設定します。

ASP.NET ページに FileUpload コントロールを追加する

図 12: ASP.NET ページに FileUpload コントロールを追加する (クリックするとフルサイズの画像が表示されます)

図 13 は、ブラウザーで表示された場合のこのページを示しています。 [参照] ボタンをクリックすると、ファイルの選択ダイアログ ボックスが表示され、ユーザーは自分のコンピューターからファイルを選択できることに注意してください。 ファイルが選択されると、[選択したファイルのアップロード] ボタンをクリックすると、選択したファイルのバイナリ コンテンツを Web サーバーに送信するポストバックが発生します。

ユーザーは、コンピューターからサーバーにアップロードするファイルを選択できます

図 13: ユーザーは自分のコンピューターからサーバーにアップロードするファイルを選択できる (クリックするとフルサイズの画像が表示されます)

ポストバックでは、アップロードされたファイルをファイル システムに保存することも、そのバイナリ データを Stream 経由で直接操作することもできます。 この例では、~/Brochures フォルダーを作成し、アップロードされたファイルをそこに保存します。 まず、Brochures フォルダーをルート ディレクトリのサブフォルダーとしてサイトに追加します。 次に、UploadButtonClick イベントのイベント ハンドラーを作成し、次のコードを追加します。

protected void UploadButton_Click(object sender, EventArgs e)
{
    if (UploadTest.HasFile == false)
    {
        // No file uploaded!
        UploadDetails.Text = "Please first select a file to upload...";            
    }
    else
    {
        // Display the uploaded file's details
        UploadDetails.Text = string.Format(
                @"Uploaded file: {0}<br />
                  File size (in bytes): {1:N0}<br />
                  Content-type: {2}", 
                  UploadTest.FileName, 
                  UploadTest.FileBytes.Length,
                  UploadTest.PostedFile.ContentType);
        // Save the file
        string filePath = 
            Server.MapPath("~/Brochures/" + UploadTest.FileName);
        UploadTest.SaveAs(filePath);
    }
}

FileUpload コントロールには、アップロードされたデータを操作するためのさまざまなプロパティが用意されています。 たとえば、HasFile プロパティは、ファイルがユーザーによってアップロードされたかどうかを示しますが、FileBytes プロパティでは、バイト配列としてアップロードされたバイナリ データへのアクセスが提供されます。 Click イベント ハンドラーは、まず、ファイルがアップロードされていることを確かめます。 ファイルがアップロードされている場合、ラベルには、アップロードされたファイルの名前、サイズ (バイト単位)、およびコンテンツ タイプが示されます。

Note

ユーザーがファイルをアップロードしていることを確かめるために、HasFile プロパティを確認し、false の場合は警告を表示するか、代わりに RequiredFieldValidator コントロールを使用できます。

FileUpload の SaveAs(filePath) では、アップロードされたファイルが指定された filePath に保存されます。 filePath virtual path (/Brochures/SomeFile.pdf) ではなく、physical path (C:\Websites\Brochures\SomeFile.pdf) である必要があります。 Server.MapPath(virtPath) メソッドでは仮想パスを受け取り、対応する物理パスを返します。 ここでは、仮想パスは ~/Brochures/fileName です。ここで、fileName はアップロードされたファイルの名前です。 仮想および物理パスと Server.MapPath の使用の詳細については、「Server.MapPath メソッド」を参照してください。

Click イベント ハンドラーが完了した後、少し時間を取ってブラウザーでページをテストします。 [参照] ボタンをクリックし、ハード ドライブからファイルを選択し、[選択したファイルのアップロード] ボタンをクリックします。 ポストバックでは、選択したファイルの内容が Web サーバーに送信され、ファイルに関する情報が表示されてから、~/Brochures フォルダーに保存されます。 ファイルをアップロードした後、Visual Studio に戻り、ソリューション エクスプローラーで [更新] ボタンをクリックします。 先ほどアップロードファイルが ~/Brochures フォルダーに表示されるはずです。

ファイル EvolutionValley.jpgが Web サーバーにアップロードされました

図 14: ファイル EvolutionValley.jpg が Web サーバーにアップロードされた (クリックするとフルサイズの画像が表示されます)

EvolutionValley.jpgが ~/Brochures フォルダーに保存されました

図 15: EvolutionValley.jpg~/Brochures フォルダーに保存された

アップロードしたファイルをファイル システムに保存する場合の微妙な点

Web サーバーのファイル システムにファイルをアップロードするときに対処する必要があるいくつかの微妙な点があります。 まず、セキュリティの問題があります。 ファイルをファイル システムに保存するには、ASP.NET ページが実行されているセキュリティ コンテキストに書き込みアクセス許可が必要です。 ASP.NET 開発 Web サーバーは、現在のユーザー アカウントのコンテキストで実行されます。 Web サーバーとして Microsoft のインターネット インフォメーション サービス (IIS) を使用している場合、セキュリティ コンテキストは IIS のバージョンとその構成によって異なります。

ファイル システムにファイルを保存する場合のもう 1 つの課題は、ファイルの名前付けに関するものです。 現在、このページでは、クライアントのコンピューター上のファイルと同じ名前を使用して、アップロードされたすべてのファイルを ~/Brochures ディレクトリに保存します。 ユーザー A が Brochure.pdf という名前のパンフレットをアップロードした場合、ファイルは ~/Brochure/Brochure.pdf として保存されます。 しかし、後でユーザー B が同じファイル名 (Brochure.pdf) を持つ別のパンフレット ファイルをアップロードした場合はどうなりますか? 現在のコードでは、ユーザー A のファイルがユーザー B がアップロードしたもので上書きされます。

ファイル名の競合を解決するためのいくつかの手法があります。 1 つのオプションは、同じ名前のものが既に存在する場合に、ファイルのアップロードを禁止することです。 この方法では、ユーザー B が Brochure.pdf という名前のファイルをアップロードしようとすると、システムによってファイルは保存されず、代わりにファイル名を変更して再試行するようにユーザー B に通知するメッセージが表示されます。 もう 1 つの方法は、一意のファイル名を使用してファイルを保存することです。これは、グローバル一意識別子 (GUID) または対応するデータベース レコードの主キー列の値である可能性があります (アップロードがデータ モデルの特定の行に関連付けられている場合)。 次のチュートリアルでは、これらのオプションについて詳しく説明します。

大量のバイナリ データに関する課題

これらのチュートリアルでは、キャプチャされるバイナリ データのサイズが小さいことを前提としています。 数メガバイト以上の非常に大量のバイナリ データ ファイルを操作すると、これらのチュートリアルの範囲を超える新しい課題が発生します。 たとえば、既定では、ASP.NET で 4 MB を超えるアップロードが拒否されますが、これは Web.config<httpRuntime> 要素を使用して構成できます。 IIS では、独自のファイル アップロード サイズの制限も課されます。 さらに、大きなファイルのアップロードにかかった時間が、ASP.NET で要求を待機する既定の 110 秒を超える可能性があります。 大きなファイルを操作するときに発生するメモリとパフォーマンスの問題もあります。

FileUpload コントロールは、大きなファイルのアップロードでは実用的ではありません。 ファイルの内容がサーバーにポストされるため、エンド ユーザーは、アップロードが進行中であることを確認することなく、辛抱強く待つ必要があります。 これは、数秒でアップロードできる小さなファイルを処理する場合はそれほど問題ではありませんが、アップロードに数分かかる可能性のある大きなファイルを処理する場合に問題になる可能性があります。 大規模なアップロードの処理により適したさまざまなサードパーティのファイル アップロード コントロールがあり、これらのベンダーの多くは進行状況インジケーターと、より洗練されたユーザー エクスペリエンスを提供する ActiveX アップロード マネージャーを提供します。

アプリケーションで大きなファイルを処理する必要がある場合は、課題を慎重に調べ、特定のニーズに適したソリューションを見つける必要があります。

まとめ

バイナリ データをキャプチャする必要があるアプリケーションを構築すると、多くの課題が発生します。 このチュートリアルでは、最初の 2 つ (バイナリ データを保存する場所を決定すること、およびユーザーが Web ページを介してバイナリ コンテンツをアップロードできるようにすること) について調べました。 次の 3 つのチュートリアルでは、アップロードされたデータをデータベース内のレコードに関連付ける方法と、バイナリ データをそのテキスト データ フィールドと共に表示する方法を確認します。

プログラミングに満足!

もっと読む

この記事で説明したトピックの詳細については、次のリソースを参照してください。

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Teresa Murphy と Bernadette Leigh でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。