データ Web コントロールにバイナリ データを表示する (VB)

作成者: Scott Mitchell

PDF のダウンロード

このチュートリアルでは、画像ファイルの表示や PDF ファイルの [ダウンロード] リンクの準備など、バイナリ データを Web ページに表示するオプションについて説明します。

はじめに

前のチュートリアルでは、バイナリ データをアプリケーションの基になるデータ モデルに関連付ける 2 つの手法を調べ、FileUpload コントロールを使用してブラウザーから Web サーバーのファイル システムにファイルをアップロードしました。 アップロードされたバイナリ データをデータ モデルに関連付ける方法はまだ確認していません。 つまり、ファイルをアップロードしてファイル システムに保存した後、ファイルへのパスを適切なデータベース レコードに格納する必要があります。 データがデータベースに直接格納されている場合は、アップロードされたバイナリ データをファイル システムに保存する必要はありませんが、データベースに挿入する必要があります。

ただし、データをデータ モデルに関連付ける前に、まず、バイナリ データをエンド ユーザーに提供する方法を見てみましょう。 テキスト データを表示するだけで十分ですが、バイナリ データはどのように表示する必要がありますか? もちろん、バイナリ データの種類によって異なります。 画像の場合は、画像を表示する必要があります。PDF、Microsoft Word ドキュメント、ZIP ファイル、およびその他の種類のバイナリ データの場合は、ダウンロード リンクを指定する方が適しています。

このチュートリアルでは、GridView や DetailsView などのデータ Web コントロールを使用して、バイナリ データを関連するテキスト データと共に表示する方法について説明します。 次のチュートリアルでは、アップロードしたファイルをデータベースに関連付けることに注目します。

手順 1: 値を指定するBrochurePath

Pictureテーブル内のCategories列には、さまざまなカテゴリ イメージのバイナリ データが既に含まれています。 具体的には、各レコードの Picture 列には、粒度の低い、低品質の 16 色のビットマップ イメージのバイナリ コンテンツが保持されます。 各カテゴリ画像は幅 172 ピクセル、高さ 120 ピクセルで、約 11 KB を消費します。 さらに、列のバイナリ コンテンツには、イメージを Picture 表示する前に削除する必要がある 78 バイト の OLE ヘッダーが含まれています。 Northwind データベースには Microsoft Access にルートがあるため、このヘッダー情報が存在します。 Access では、バイナリ データは OLE Object データ型を使用して格納されます。このデータ型は、このヘッダーに付きます。 ここでは、画像を表示するために、これらの低品質の画像からヘッダーを削除する方法について説明します。 今後のチュートリアルでは、カテゴリの Picture 列を更新するためのインターフェイスを構築し、OLE ヘッダーを使用するビットマップ イメージを、不要な OLE ヘッダーなしで同等の JPG イメージに置き換えます。

前のチュートリアルでは、FileUpload コントロールの使用方法を確認しました。 そのため、Web サーバーのファイル システムにパンフレット ファイルを追加できます。 ただし、これを行っても、テーブル内の列はBrochurePathCategories更新されません。 次のチュートリアルでは、これを実現する方法について説明しますが、ここでは、この列の値を手動で指定する必要があります。

このチュートリアルのダウンロードでは、7 つの PDF パンフレット ファイルが ~/Brochures フォルダー内にあります。1 つは、シーフードを除くカテゴリごとに 1 つです。 すべてのレコードにバイナリ データが関連付けられていないシナリオを処理する方法を示すために、シーフードパンフレットを追加することを意図的に省略しました。 これらの値でテーブルをCategories更新するには、[サーバー エクスプローラー] からノードをCategories右クリックし、[テーブル データの表示] を選択します。 次に、図 1 に示すように、パンフレットを含む各カテゴリのパンフレット ファイルへの仮想パスを入力します。 シーフード カテゴリのパンフレットはないため、 BrochurePath 列の値は のままに NULLします。

Categories テーブルの BrochurePath 列の値を手動で入力する

図 1: テーブルの列の値をCategories手動で入力する (フルサイズのBrochurePath画像を表示する をクリックします)

テーブルに指定CategoriesされたBrochurePath値を使用して、カテゴリのパンフレットをダウンロードするためのリンクと共に各カテゴリを一覧表示する GridView を作成する準備ができました。 手順 4 では、この GridView を拡張して、カテゴリの画像も表示します。

まず、ツールボックスからフォルダー内のページのDisplayOrDownloadData.aspxDesignerに GridView をBinaryDataドラッグします。 GridView の ID スマート タグを使用して Categories GridView を に設定し、新しいデータ ソースにバインドすることを選択します。 具体的には、オブジェクトの GetCategories() メソッドを使用してデータを取得する という名前CategoriesDataSourceの ObjectDataSource にCategoriesBLLバインドします。

新しい ObjectDataSource 名前付き CategoriesDataSource を作成する

図 2: 名前付きの CategoriesDataSource 新しい ObjectDataSource を作成する (フルサイズの画像を表示する場合はクリックします)

CategoriesBLL クラスを使用するように ObjectDataSource を構成する

図 3: クラスを使用するように ObjectDataSource を構成する CategoriesBLL (フルサイズの画像を表示するにはクリックします)

GetCategories() メソッドを使用してカテゴリのリストを取得する

図 4: メソッドを使用してカテゴリの一覧を GetCategories() 取得する (フルサイズの画像を表示する をクリックします)

データ ソースの構成ウィザードが完了すると、Visual Studio によって、および BrochurePathの BoundField が GridView CategoryIDNumberOfProductsCategoryNameDescriptionCategories自動的に追加されます。DataColumn メソッドのクエリではこの情報が NumberOfProducts 取得されないため、先に GetCategories() 進んで BoundField を削除してください。 また、BoundField を CategoryID 削除し、 CategoryName プロパティと BrochurePath BoundFields HeaderText プロパティの名前をそれぞれ Category プロパティと Brochure プロパティに変更します。 これらの変更を行った後、GridView と ObjectDataSource の宣言型マークアップは次のようになります。

<asp:GridView ID="Categories" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="CategoryID"
    DataSourceID="CategoriesDataSource" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
        <asp:BoundField DataField="BrochurePath" HeaderText="Brochure" 
            SortExpression="BrochurePath" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

ブラウザーでこのページを表示します (図 5 を参照)。 8 つのカテゴリのそれぞれが一覧表示されます。 値を持つ BrochurePath 7 つのカテゴリには、 BrochurePath それぞれの BoundField に値が表示されます。 の値BrochurePathNULL持つシーフードには、空のセルが表示されます。

各カテゴリの名前、説明、およびパンフレットパスの値が一覧表示されます

図 5: 各カテゴリの名前、説明、および BrochurePath 値が一覧表示されている (フルサイズの画像を表示するをクリックします)

列の BrochurePath テキストを表示するのではなく、パンフレットへのリンクを作成します。 これを行うには、BoundField を BrochurePath 削除し、HyperLinkField に置き換えます。 新しい HyperLinkField の HeaderText プロパティを [パンフレット] に設定し、その Text プロパティを [パンフレットの表示] に設定し、その DataNavigateUrlFields プロパティを に BrochurePath設定します。

BrochurePath の HyperLinkField を追加する

図 6: の HyperLinkField を追加する BrochurePath

これにより、図 7 に示すように、GridView へのリンクの列が追加されます。 [パンフレットの表示] リンクをクリックすると、PDF リーダーがインストールされているかどうかとブラウザーの設定に応じて、PDF がブラウザーに直接表示されるか、ファイルのダウンロードを求められます。

カテゴリのパンフレットは、パンフレットの表示リンクをクリックして表示できます

図 7: カタログの表示リンクをクリックすると、カテゴリのパンフレットを表示できます (フルサイズの画像を表示する をクリックします)

カテゴリのパンフレット PDF が表示されます

図 8: カテゴリのパンフレット PDF が表示されている (フルサイズの画像を表示するをクリックします)

パンフレットのないカテゴリのビュー パンフレット テキストを非表示にする

図 7 に示すように、BrochurePathHyperLinkField には、 に非NULL値があるかどうかに関係なく、すべてのレコードのプロパティ値 BrochurePath(パンフレットの表示) が表示されますText。 もちろん、 が NULLの場合BrochurePathは、シーフード カテゴリの場合と同様に、リンクはテキストとしてのみ表示されます (図 7 を参照)。 [パンフレットの表示] というテキストを表示するのではなく、値のない BrochurePath カテゴリに代替テキスト ([パンフレットなし] など) を表示すると便利な場合があります。

この動作を提供するには、値に基づいて適切な出力を出力するページ メソッドの呼び出しによってコンテンツが生成される TemplateField を使用する BrochurePath 必要があります。 最初に、 GridView コントロールの TemplateFields の使用 に関するチュートリアルで、この書式設定手法について確認しました。

HyperLinkField を選択し、[列の編集] ダイアログ ボックスの [このフィールドを BrochurePath TemplateField に変換する] リンクをクリックして、HyperLinkField を TemplateField に変換します。

HyperLinkField を TemplateField に変換する

図 9: HyperLinkField を TemplateField に変換する

これにより、プロパティが値にバインドされている HyperLink Web コントロールを含む を持つ ItemTemplateNavigateUrl TemplateField が BrochurePath 作成されます。 このマークアップを メソッド GenerateBrochureLinkの呼び出しに置き換え、 の BrochurePath値を渡します。

<asp:TemplateField HeaderText="Brochure">
    <ItemTemplate>
        <%# GenerateBrochureLink(Eval("BrochurePath")) %>
    </ItemTemplate>
</asp:TemplateField>

次に、 を返Stringし、 を入力パラメーターとして受け入れる という名前GenerateBrochureLinkのメソッドを、ASP.NET ページのObject分離コード クラスに作成Protectedします。

Protected Function GenerateBrochureLink(BrochurePath As Object) As String
    If Convert.IsDBNull(BrochurePath) Then
        Return "No Brochure Available"
    Else
        Return String.Format("<a href="{0}">View Brochure</a>", _
            ResolveUrl(BrochurePath.ToString()))
    End If
End Function

このメソッドは、渡された Object 値がデータベース NULL であるかどうかを判断し、存在する場合は、カテゴリにパンフレットがないことを示すメッセージを返します。 それ以外の場合は、値がある BrochurePath 場合はハイパーリンクで表示されます。 値が存在するBrochurePath場合は、 メソッドにResolveUrl(url)渡されることに注意してください。 このメソッドは、渡された URL を解決し、文字を ~ 適切な仮想パスに置き換えます。 たとえば、アプリケーションが で/Tutorial55ResolveUrl("~/Brochures/Meats.pdf")ルート化されている場合、 は を返します/Tutorial55/Brochures/Meat.pdf

図 10 は、これらの変更が適用された後のページを示しています。 [シーフード カテゴリ] フィールドに BrochurePath [パンフレットなし] というテキストが表示されるようになりました。

パンフレットのない分類項目については、利用可能なパンフレットがないテキストが表示されます

図 10: パンフレットのないカテゴリに対して利用可能なパンフレットがないテキストが表示される (フルサイズの画像を表示する をクリックします)

手順 3: カテゴリの画像を表示する Web ページを追加する

ユーザーは、ASP.NET ページにアクセスすると、ASP.NET ページの HTML を受け取ります。 受信した HTML は単なるテキストであり、バイナリ データは含まれません。 画像、サウンド ファイル、Macromedia Flash アプリケーション、埋め込みWindows メディア プレーヤービデオなどの追加のバイナリ データは、Web サーバー上に個別のリソースとして存在します。 HTML にはこれらのファイルへの参照が含まれていますが、ファイルの実際の内容は含まれません。

たとえば、HTML では、 要素は <img> 画像を参照するために使用され、 属性は src 次のように画像ファイルを指します。

<img src="MyPicture.jpg" ... />

ブラウザーは、この HTML を受信すると、イメージ ファイルのバイナリ コンテンツを取得するように Web サーバーに別の要求を行い、ブラウザーに表示します。 バイナリ データにも同じ概念が適用されます。 手順 2 では、パンフレットはページの HTML マークアップの一部としてブラウザーに送信されませんでした。 代わりに、レンダリングされた HTML はハイパーリンクを提供し、クリックするとブラウザーが PDF ドキュメントを直接要求する原因となったのです。

ユーザーがデータベース内に存在するバイナリ データを表示またはダウンロードできるようにするには、データを返す別の Web ページを作成する必要があります。 アプリケーションの場合、カテゴリの画像をデータベースに直接格納するバイナリ データ フィールドは 1 つだけです。 したがって、呼び出されると、特定のカテゴリの画像データを返すページが必要です。

という名前DisplayCategoryPicture.aspxのフォルダーに新しい ASP.NET ページをBinaryData追加します。 この場合は、[マスター ページの選択] チェック ボックスをオフのままにします。 このページでは、 CategoryID querystring の値が想定され、そのカテゴリの Picture 列のバイナリ データが返されます。 このページはバイナリ データを返し、それ以外は何も返さないので、HTML セクションにマークアップは必要ありません。 そのため、左下隅にある [ソース] タブをクリックし、 ディレクティブを除くすべてのページマークアップを <%@ Page %> 削除します。 つまり、 DisplayCategoryPicture.aspx 宣言型マークアップは 1 行で構成する必要があります。

<%@ Page Language="VB" AutoEventWireup="true" 
    CodeFile="DisplayCategoryPicture.aspx.vb" 
    Inherits="BinaryData_DisplayCategoryPicture" %>

ディレクティブに 属性が表示された MasterPageFile 場合は <%@ Page %> 、それを削除します。

ページの分離コード クラスで、次のコードをイベント ハンドラーに Page_Load 追加します。

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim categoryID As Integer = _
        Convert.ToInt32(Request.QueryString("CategoryID"))
    ' Get information about the specified category
    Dim categoryAPI As New CategoriesBLL()
    Dim categories As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categories(0)
    ' Output HTTP headers providing information about the binary data
    Response.ContentType = "image/bmp"
    ' Output the binary data
    ' But first we need to strip out the OLE header
    Const OleHeaderLength As Integer = 78
    Dim strippedImageLength As Integer = _
        category.Picture.Length - OleHeaderLength
    Dim strippedImageData(strippedImageLength) As Byte
    Array.Copy(category.Picture, OleHeaderLength, _
        strippedImageData, 0, strippedImageLength)
    Response.BinaryWrite(strippedImageData)
End Sub

このコードは、まず、querystring 値を CategoryID という名前 categoryIDの変数に読み込むことから始めます。 次に、画像データは クラスの GetCategoryWithBinaryDataByCategoryID(categoryID) メソッドの呼び出しをCategoriesBLL介して取得されます。 このデータは メソッドを使用 Response.BinaryWrite(data) してクライアントに返されますが、これを呼び出す前に、列値の OLE ヘッダーを Picture 削除する必要があります。 これを行うには、 という名前strippedImageDataByte配列を作成します。この配列は、列のPicture文字数より正確に 78 文字少なくなります。 メソッドはArray.Copy、位置 78 から にデータcategory.PictureをコピーするためにstrippedImageData使用されます。

プロパティは Response.ContentType 、返されるコンテンツの MIME の種類 を指定して、ブラウザーがそれをレンダリングする方法を認識できるようにします。 テーブルのCategoriesPicture列はビットマップ イメージであるため、ここではビットマップ MIME の種類 (image/bmp) が使用されます。 MIME の種類を省略しても、ほとんどのブラウザーでは、画像ファイルのバイナリ データの内容に基づいて型を推論できるため、画像が正しく表示されます。 ただし、可能であれば MIME の種類を含めるのが賢明です。 MIME メディアの種類の完全な一覧については、インターネット割り当て番号局の Web サイトを参照してください。

このページを作成すると、 にアクセスして特定のカテゴリの画像を DisplayCategoryPicture.aspx?CategoryID=categoryID表示できます。 図 11 は、飲料カテゴリの画像を示しています。これは から DisplayCategoryPicture.aspx?CategoryID=1表示できます。

飲料カテゴリの画像が表示される

図 11: 飲料カテゴリの画像が表示されている (フルサイズの画像を表示する をクリックします)

DisplayCategoryPicture.aspx?CategoryID=categoryIDアクセスすると、'System.DBNull' 型のオブジェクトを 'System.Byte[]' 型にキャストできないという例外が発生します。この原因は 2 つあります。 まず、 Categories テーブルの列で Picture 値が許可 NULL されます。 ただし、ページには DisplayCategoryPicture.aspx 値以外NULL の値が存在することを前提としています。 Pictureの プロパティに値があるNULL場合は、 のプロパティCategoriesDataTableに直接アクセスできません。 列の値Pictureを許可NULLする場合は、次の条件を含めます。

If category.IsPictureNull() Then
    ' Display some "No Image Available" picture
    Response.Redirect("~/Images/NoPictureAvailable.gif")
Else
    ' Send back the binary contents of the Picture column
    ' ... Set ContentType property and write out ...
    ' ... data via Response.BinaryWrite ...
End If

上記のコードでは、画像のないカテゴリにImages対して表示するという名前NoPictureAvailable.gifのイメージ ファイルがフォルダー内にあることを前提としています。

この例外は、s メソッドの GetCategoryWithBinaryDataByCategoryIDSELECT ステートメントが メイン クエリの列リストに戻った場合CategoriesTableAdapterにも発生する可能性があります。これは、アドホック SQL ステートメントを使用していて、TableAdapter の メイン クエリのウィザードを再実行した場合に発生する可能性があります。 メソッドの SELECT ステートメントに列がまだGetCategoryWithBinaryDataByCategoryID含まれていることをPicture確認します。

注意

DisplayCategoryPicture.aspx アクセスするたびに、データベースにアクセスし、指定されたカテゴリの画像データが返されます。 ただし、ユーザーが最後に表示してからカテゴリの画像が変更されていない場合、これは無駄な作業です。 幸いなことに、HTTP では 条件付き GET が許可されます。 条件付き GET を使用すると、HTTP 要求を行うクライアントは、クライアントが Web サーバーからこのリソースをIf-Modified-Since最後に取得した日時を提供する HTTP ヘッダーに沿って送信します。 この指定された日付以降にコンテンツが変更されていない場合、Web サーバーは 未変更状態コード (304) で応答し、要求されたリソースのコンテンツの送信を見送る可能性があります。 つまり、この手法を使用すると、クライアントが最後にアクセスしてから変更されていない場合に、Web サーバーがリソースのコンテンツを返送する必要が解消されます。

ただし、この動作を実装するには、列が最後に更新されたときにPictureキャプチャするCategories列と、ヘッダーのチェックするコードをテーブルに追加PictureLastModifiedするIf-Modified-Since必要があります。 ヘッダーと条件付き GET ワークフローの If-Modified-Since 詳細については、「 HTTP Conditional GET for RSS Hackers 」および「 ASP.NET ページでの HTTP 要求の実行の詳細」を参照してください。

手順 4: GridView でカテゴリ画像を表示する

特定のカテゴリの画像を表示する Web ページが作成されたので、 Image Web コントロール または を指す HTML <img> 要素を DisplayCategoryPicture.aspx?CategoryID=categoryID使用して表示できます。 データベース データによって URL が決定されたイメージは、ImageField を使用して GridView または DetailsView に表示できます。 ImageField には、DataImageUrlFieldHyperLinkField DataNavigateUrlFieldsDataImageUrlFormatStringプロパティと同様に機能する プロパティと DataNavigateUrlFormatString プロパティが含まれています。

では、ImageField を Categories 追加して GridView DisplayOrDownloadData.aspx を拡張し、各カテゴリの画像を表示してみましょう。 ImageField を追加し、その DataImageUrlField プロパティと DataImageUrlFormatString プロパティをそれぞれ と DisplayCategoryPicture.aspx?CategoryID={0}CategoryID設定するだけです。 これにより、属性が を参照DisplayCategoryPicture.aspx?CategoryID={0}する要素src<img>レンダリングする GridView 列が作成されます。ここで{0}、 は GridView 行のCategoryID値に置き換えられます。

GridView に ImageField を追加する

図 12: GridView に ImageField を追加する

ImageField を追加すると、GridView の宣言型構文は次のようになるはずです。

<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
        <asp:TemplateField HeaderText="Brochure">
            <ItemTemplate>
                <%# GenerateBrochureLink(Eval("BrochurePath")) %>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:ImageField DataImageUrlField="CategoryID" 
            DataImageUrlFormatString="DisplayCategoryPicture.aspx?CategoryID={0}">
        </asp:ImageField>
    </Columns>
</asp:GridView>

ブラウザーからこのページを表示するには、少し時間を取ります。 各レコードにカテゴリの画像が含まれるようになったことに注意してください。

各行に対してカテゴリの図が表示されます

図 13: 各行のカテゴリの図が表示されます (フルサイズの画像を表示する をクリックします)。

まとめ

このチュートリアルでは、バイナリ データを表示する方法について説明しました。 データの表示方法は、データの種類によって異なります。 PDF パンフレット ファイルの場合、クリックするとユーザーを PDF ファイルに直接移動する [パンフレットの表示] リンクをユーザーに提供しました。 カテゴリの図では、まずデータベースからバイナリ データを取得して返すページを作成し、そのページを使用して各カテゴリの画像を GridView に表示しました。

バイナリ データを表示する方法を確認したので、バイナリ データを使用してデータベースに対して挿入、更新、および削除を実行する方法を確認する準備ができました。 次のチュートリアルでは、アップロードしたファイルを対応するデータベース レコードに関連付ける方法について説明します。 その後のチュートリアルでは、既存のバイナリ データを更新する方法と、関連するレコードが削除されたときにバイナリ データを削除する方法について説明します。

幸せなプログラミング!

著者について

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

特別な感謝

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