ストリーミング プロバイダー (WCF Data Services)

データ サービスは、ラージ オブジェクトのバイナリ データを公開できます。 このバイナリ データは、ビデオ ストリームとオーディオ ストリーム、画像、ドキュメント ファイル、またはその他の種類のバイナリのメディアを表すことができます。 データ モデルのエンティティに 1 つ以上のバイナリ プロパティが含まれている場合、データ サービスは、このバイナリ データを応答フィードのエントリ内に Base-64 としてエンコードして返します。 この方法で大きなバイナリ データを読み込んでシリアル化するとパフォーマンスに影響を及ぼす可能性があるため、Open Data Protocol (OData) では、属するエンティティとは独立してバイナリ データを取得するためのメカニズムが定義されています。 これは、バイナリ データとエンティティを分離して 1 つ以上のデータ ストリームを生成することで実現されます。

OData プロトコルでは、エンティティに関連するストリームとしてバイナリ データを公開するための次の 2 つのメカニズムをサポートしています。

  • メディア リソース/メディア リンク エントリ

    Atom 公開プロトコル (AtomPub) は、メディア エントリ リンクと呼ばれる、バイナリ データをメディア リソースとしてデータ フィード内のエントリに関連付けるためのメカニズムを定義します。 特定のメディア リンク エントリに対して定義できるメディア リソースは 1 つだけです。 メディア リソースは、エンティティの既定のストリームと見なすことができます。 OData は、このストリーミング動作を AtomPub から継承します。

  • 名前付きリソース ストリーム

    OData Version 3 より、1 つのエンティティが複数の関連リソース ストリームを持つことができます。これらは、名前でアクセスされます。 このメカニズムは AtomPub に依存しないため、メディア リンク エントリとして設定することなく、1 つのエンティティに複数の名前付きリソース ストリームを関連付けることが可能になりました。 また、メディア リンク エントリに名前付きストリームを関連付けることもできます。 詳細については、次のトピックを参照してください。、ブログの記事「名前付きリソース ストリーム」を参照してください。

WCF Data Services では、ストリーミング データ プロバイダーを実装してバイナリ リソース ストリームを定義します。 ストリーミング プロバイダーを実装すると、Stream オブジェクトとして特定のエンティティに関連付けられているストリームがデータ サービスに提供されます。

バイナリ データのストリーミングをサポートするデータ サービスを構成するには、次の手順に従う必要があります。

  1. 関連リソース ストリームを持つ、データ モデル内のエンティティの属性を設定します。 それぞれのデータ プロバイダーには、独自の要件があります。それぞれの種類のバイナリ リソース ストリームは、データ モデル内で異なるメカニズムによって定義されます。

  2. 次のストリーム プロバイダーのインターフェイスを実装します。

  3. IServiceProvider インターフェイスを実装するデータ サービスを定義します。 データ サービスは、GetService の実装を使用してストリーミング データ プロバイダーの実装にアクセスします。 このメソッドは、適切なストリーミング プロバイダーの実装を返します。

  4. Web アプリケーション構成で大きいメッセージ ストリームを有効にします。

  5. サーバー上またはデータ ソース内のバイナリ リソースへのアクセスを有効にします。

このトピックの例はサンプルのストリーミング フォト サービスに基づいています。詳細については、ブログの記事「Data Services ストリーミング プロバイダー シリーズ: ストリーミング プロバイダーの実装 (パート 1)」を参照してください。 このサンプル サービスのソース コードは、MSDN コード ギャラリーのストリーミング フォト データ サービスのサンプル ページで入手できます。

データ モデルでのリソース ストリームの定義

バイナリ リソース ストリームをデータ モデルで定義する方法は、使用されているデータ ソース プロバイダーに加えて、ストリームがメディア リソースと名前付きリソース ストリームのどちらであるかによって異なります。 次の例に、データ サービスによって返されるメタデータ内のメディア リソースの定義を示します。ここで、PhotoInfo は、名前付きリソース ストリーム (Thumbnail) も定義されているメディア リンク エントリです。

<EntityType Name="PhotoInfo" m:HasStream="true">
  <Key>
    <PropertyRef Name="PhotoId" />
  </Key>
  <Property Name="PhotoId" Type="Edm.Int32" Nullable="false" 
            p9:StoreGeneratedPattern="Identity" 
            xmlns:p9="https://schemas.microsoft.com/ado/2009/02/edm/annotation" />
  <Property Name="FileName" Type="Edm.String" Nullable="false" />
  <Property Name="FileSize" Type="Edm.Int32" Nullable="true" />
  <Property Name="DateTaken" Type="Edm.DateTime" Nullable="true" />
  <Property Name="TakenBy" Type="Edm.String" Nullable="true" />
  <Property Name="DateAdded" Type="Edm.DateTime" Nullable="false" />
  <Property Name="Exposure" Type="PhotoData.Exposure" Nullable="false" />
  <Property Name="Dimensions" Type="PhotoData.Dimensions" Nullable="false" />
  <Property Name="DateModified" Type="Edm.DateTime" Nullable="false" />
  <Property Name="Comments" Type="Edm.String" Nullable="true" MaxLength="Max" 
            Unicode="true" FixedLength="false" />
  <Property Name="ContentType" Type="Edm.String" Nullable="true" MaxLength="50" 
            Unicode="true" FixedLength="false" />
  <Property Name="Thumbnail" Type="Edm.Stream" Nullable="false" />
</EntityType>

Entity Framework プロバイダー

Entity Framework プロバイダーを使用する場合、ストリームの種類に応じて次のいずれかの方法を使用して、データ モデル自体にバイナリ リソース ストリームを定義します。

  • メディア リソース ストリーム:

    エンティティが関連メディア リソースを持つメディア リンク エントリであることを示すには、概念モデルのエンティティ型定義に HasStream 属性を追加します。 さらに、名前空間 xmlns:m=https://schemas.microsoft.com/ado/2007/08/dataservices/metadata への参照をメディア リンク エントリまたはデータ モデル内のいずれかの親要素に追加する必要があります。

  • 名前付きリソース ストリーム:

    メディア リンク エントリに属している名前付きストリームは、概念モデルの Stream 型のプロパティとして定義されします。

    重要

    Stream データ型は、Entity Data Model (EDM) Version 2.2 以降でサポートされます。ただし、.NET Framework 4 では、Entity Framework は EDM のこのバージョンをサポートしていません。対処法として、代わりに、エンティティを表すデータ モデル オブジェクト レイヤーのクラスに NamedStreamAttribute を適用することによって、名前付きリソース ストリームをデータ モデルに定義できます。この属性において、name パラメーターはストリームの名前です。エンティティ クラスにこの属性を追加する際は、別個のコード ファイルに部分クラス定義を作成することをお勧めします。そうしておかないと、Entity Framework によってエンティティ データ クラスが再生成されたときにこのカスタマイズが上書きされます。リフレクション プロバイダーと同様、データ サービスは、Stream 型の指定された name のプロパティをデータ モデルに生成します。

Entity Framework プロバイダーを使用したメディア リソースの公開の例については、ブログの記事「Data Services ストリーミング プロバイダー シリーズ: ストリーミング プロバイダーの実装 (パート 1)」を参照してください。

リフレクション プロバイダー

リフレクション プロバイダーを使用する場合、ストリームの種類に応じた次のいずれかの方法で属性をエンティティ型であるクラスに適用することによって、バイナリ リソース ストリームがエンティティ型に属していることを示します。

  • メディア リソース ストリーム:

    HasStreamAttribute を適用して、メディア リンク エントリである型に属しているメディア リソース (既定) ストリームを定義します。

  • 名前付きリソース ストリーム:

    NamedStreamAttribute を適用して、エンティティ型に属している名前付きリソース ストリームを定義します。name パラメーターには、ストリームの名前を指定します。

カスタム データ サービス プロバイダー

カスタム サービス プロバイダーを使用する場合は、IDataServiceMetadataProvider インターフェイスを実装してデータ サービスのメタデータを定義します。 詳細については、「カスタム データ サービス プロバイダー (WCF Data Services)」を参照してください。 次のいずれかの方法を使用して、バイナリ リソース ストリームが ResourceType に属することを示します。

ストリーム プロバイダーのインターフェイスの実装

バイナリ データ ストリームをサポートするデータ サービスを作成するには、少なくとも IDataServiceStreamProvider インターフェイスを実装する必要があります。 これを実装すると、データ サービスはバイナリ データをストリームとしてクライアントに返し、クライアントから送信されたストリームとしてバイナリ データを使用できます。 名前付きストリームをサポートするには、さらに IDataServiceStreamProvider2 インターフェイスも実装する必要があります。 データ サービスでは、ストリームとしてのバイナリ データへのアクセスが必要になるたびに、適切なインターフェイスのインスタンスを作成します。

IDataServiceStreamProvider

IDataServiceStreamProvider インターフェイスでは次のメンバーを指定します。

メンバー名

説明

DeleteStream

このメソッドはデータ サービスにより呼び出され、そのメディア リンク エントリが削除されたときに対応するメディア リソースと名前付きストリームの両方を削除します。 IDataServiceStreamProvider を実装する場合、このメソッドには、指定されたメディア リンク エントリに関連付けられたストリーミング対象のバイナリ データをすべて削除するコードが含まれます。

GetReadStream

このメソッドはデータ サービスにより呼び出され、メディア リソースをストリームとして返します。 IDataServiceStreamProvider を実装する場合、このメソッドには、指定されたメディア リンク エントリに関連付けられたメディア リソースを返すためにデータ サービスが使用するストリームを提供するコードが含まれます。

GetReadStreamUri

このメソッドはデータ サービスにより呼び出され、メディア リンク エントリのメディア リソースを要求するために使用される URI を返します。 この値を使用して、メディア リンク エントリのコンテンツ要素の src 属性が作成され、データ ストリームが要求されます。 このメソッドから null が返されると、データ サービスによって URI が自動的に決定されます。 このメソッドは、ストリーミング プロバイダーを使用しないバイナリ データへの直接アクセスをクライアントに提供する必要がある場合に使用します。

GetStreamContentType

このメソッドはデータ サービスにより呼び出され、指定されたメディア リンク エントリに関連付けられたメディア リソースの Content-Type 値を返します。

GetStreamETag

このメソッドはデータ サービスにより呼び出され、指定されたエンティティに関連付けられたデータ ストリームの eTag を返します。 このメソッドは、バイナリ データの同時実行を管理する場合に使用されます。 このメソッドが null を返す場合、データ サービスでは同時実行が追跡されません。

GetWriteStream

このメソッドはデータ サービスにより呼び出され、クライアントから送信されたストリームの受信時に使用されるストリームを取得します。 IDataServiceStreamProvider を実装する場合、データ サービスが受信したストリーム データを書き込む先である書き込み可能なストリームを返す必要があります。

ResolveType

名前空間で修飾された型名を返します。この型は、挿入されるメディア リソースのデータ ストリームに関連付けられたメディア リンク エントリに対してデータ サービス ランタイムが作成する必要がある型を表します。

IDataServiceStreamProvider2

IDataServiceStreamProvider2 インターフェイスは、IDataServiceStreamProvider のメンバーをオーバーロードして名前付きリソース ストリームである ResourceProperty パラメーターを受け取る次のメンバーを指定します。

メンバー名

説明

GetReadStream(Object, ResourceProperty, String, Nullable<Boolean>, DataServiceOperationContext)

このメソッドはデータ サービスにより呼び出され、名前付きストリームを返します。 IDataServiceStreamProvider2 を実装する場合、このメソッドには、指定されたメディア リンク エントリに関連付けられた要求された名前付きストリームを返すためにデータ サービスが使用するストリームを提供するコードが含まれます。

GetReadStreamUri(Object, ResourceProperty, DataServiceOperationContext)

このメソッドはデータ サービスにより呼び出され、メディア リンク エントリの特定の名前付きストリームを要求するために使用される URI を返します。 この値は、名前付きストリームを要求するための atom:link 要素を作成するために使用されます。 このメソッドから null が返されると、データ サービスによって URI が自動的に決定されます。 このメソッドは、ストリーミング プロバイダーを使用しないバイナリ データへの直接アクセスをクライアントに提供する必要がある場合に使用します。

GetStreamContentType(Object, ResourceProperty, DataServiceOperationContext)

このメソッドはデータ サービスにより呼び出され、指定されたメディア リンク エントリに関連付けられた特定の名前付きストリームの Content-Type 値を返します。

GetStreamETag(Object, ResourceProperty, DataServiceOperationContext)

このメソッドはデータ サービスにより呼び出され、指定されたエンティティに関連付けられた特定の名前付きストリームの eTag を返します。 このメソッドは、バイナリ データの同時実行を管理する場合に使用されます。 このメソッドが null を返す場合、データ サービスでは同時実行が追跡されません。

GetWriteStream(Object, ResourceProperty, String, Nullable<Boolean>, DataServiceOperationContext)

このメソッドはデータ サービスにより呼び出され、クライアントから送信された名前付きストリームの受信時に使用されるストリームを取得します。 IDataServiceStreamProvider2 を実装する場合、データ サービスが受信したストリーム データを書き込む先である書き込み可能なストリームを返す必要があります。

ストリーミング データ サービスの作成

WCF Data Services ランタイムに IDataServiceStreamProvider および IDataServiceStreamProvider2 の実装へのアクセスを提供するには、作成するデータ サービスで IServiceProvider インターフェイスも実装する必要があります。 次の例は、GetService メソッドを実装して、IDataServiceStreamProviderIDataServiceStreamProvider2 を実装する PhotoServiceStreamProvider クラスのインスタンスを返す方法を示しています。

Partial Public Class PhotoData
    Inherits DataService(Of PhotoDataContainer)
    Implements IServiceProvider

    ' This method is called only once to initialize service-wide policies.
    Public Shared Sub InitializeService(ByVal config As DataServiceConfiguration)
        config.SetEntitySetAccessRule("PhotoInfo", _
            EntitySetRights.ReadMultiple Or _
            EntitySetRights.ReadSingle Or _
            EntitySetRights.AllWrite)

        ' Named streams require version 3 of the OData protocol.
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3
    End Sub
#Region "IServiceProvider Members"
    Public Function GetService(ByVal serviceType As Type) As Object _
    Implements IServiceProvider.GetService
        If serviceType Is GetType(IDataServiceStreamProvider) _
            Or serviceType Is GetType(IDataServiceStreamProvider2) Then
            Return New PhotoServiceStreamProvider(Me.CurrentDataSource)
        End If
        Return Nothing
    End Function
#End Region
End Class
public partial class PhotoData : DataService<PhotoDataContainer>, IServiceProvider
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("PhotoInfo",
            EntitySetRights.ReadMultiple |
            EntitySetRights.ReadSingle |
            EntitySetRights.AllWrite);

        // Named resource streams require version 3 of the OData protocol.
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
    public object GetService(Type serviceType)
    {
        if (serviceType == typeof(IDataServiceStreamProvider2))
        {
            // Return the stream provider to the data service.
            return new PhotoServiceStreamProvider(this.CurrentDataSource);
        }

        return null;
    }
}

データ サービスの作成方法に関する一般的な情報については、「データ サービスの構成 (WCF Data Services)」を参照してください。

ホスト環境での大きなバイナリ ストリームの有効化

ASP.NET Web アプリケーションのデータ サービスを作成する場合、Windows Communication Foundation (WCF) を使用して HTTP プロトコルが実装されます。既定では、WCF では HTTP メッセージのサイズは 65K バイトのみに制限されます。 また、データ サービスに対する大きなバイナリ データのストリーミングを可能にするには、大きなバイナリ ファイルを有効にして、転送にストリームを使用するように Web アプリケーションを構成する必要もあります。 そのためには、アプリケーションの Web.config ファイルの <configuration /> 要素に次の内容を追加します。

    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
            <!-- The name of the service -->
            <service name="PhotoService.PhotoData">
                <!--you can leave the address blank or specify your end point URI-->
                <endpoint binding="webHttpBinding" bindingConfiguration="higherMessageSize" 
                  contract="System.Data.Services.IRequestHandler"></endpoint>
            </service>
        </services>
        <bindings>
            <webHttpBinding>
                <!-- configure the maxReceivedMessageSize value to suit the max size of 
   the request (in bytes) you want the service to receive-->
                <binding name="higherMessageSize" transferMode="Streamed"  
                 maxReceivedMessageSize="2147483647"/>
            </webHttpBinding>
        </bindings>
    </system.serviceModel>

注意

TransferMode.Streamed 転送モードを使用して、要求メッセージと応答メッセージの両方のバイナリ データをストリーミングし、WCF によってバッファリングされないようにする必要があります。

詳細については、「Streaming Message Transfer」および「Transport Quotas」を参照してください。

また、既定では、インターネット インフォメーション サービス (IIS) でも要求のサイズが 4 MB に制限されます。 IIS 上で実行時にデータ サービスが 4 MB を超えるストリームを受信できるようにするには、次の例に示すように、<system.web /> 構成セクション内の httpRuntime Element の maxRequestLength 属性を設定する必要があります。

  <system.web>
        <!-- maxRequestLength (in KB): default=4000 (4MB); max size=2048MB. -->
        <httpRuntime maxRequestLength="2000000"/>
  </system.web>

クライアント アプリケーションでのデータ ストリームの使用

バイナリ データ ストリームは、次の URI のいずれかを使用して直接アクセスできます。

  • メディア リソース ストリーム:

    https://localhost/PhotoService/PhotoData.svc/PhotoInfo(1)/$value
    
  • 名前付きリソース ストリーム:

    https://localhost/PhotoService/PhotoData.svc/PhotoInfo(1)/Thumbnail
    

WCF Data Services クライアント ライブラリを使用すると、クライアントのバイナリ ストリームとして公開されたリソースを取得および更新できます。 詳細については、「バイナリ データの操作 (WCF Data Services)」を参照してください。

ストリーミング プロバイダーの使用に関する考慮事項

ストリーミング プロバイダーを実装する場合およびデータ サービスからメディア リソースにアクセスする場合には、次の点を考慮してください。

  • メディア リソースまたは名前付きリソース ストリームをサポートする場合は、IDataServiceStreamProvider インターフェイスを実装する必要があります。 名前付きリソース ストリームをサポートするには、さらに IDataServiceStreamProvider2 インターフェイスも実装する必要があります。

  • メディア リンク エントリに属している名前付きリソース ストリームを定義する場合、データ モデルで定義されているエンティティにストリームと同じ名前を持つプロパティを含めることはできません。

  • MERGE 要求は、メディア リソースではサポートされません。 既存のエンティティのメディア リソースを変更するには、PUT 要求を使用します。

  • POST 要求を使用して新しいメディア リンク エントリを作成することはできません。 代わりに、POST 要求を発行して新しいメディア リソースを作成する必要があります。データ サービスによって、既定値で新しいメディア リンク エントリが作成されます。 その後に MERGE 要求または PUT 要求を使用してこの新しいエンティティを更新できます。 プロパティ値を POST 要求の Slug ヘッダーの値に設定するなど、エンティティをキャッシュしてディスポーザーで更新を行うこともできます。

  • POST 要求を受信すると、データ サービスは GetWriteStream を呼び出してメディア リソースを作成してから、SaveChanges を呼び出してメディア リンク エントリを作成します。

  • GetWriteStream を実装すると、MemoryStream オブジェクトは返されません。 この種類のストリームを使用すると、サービスが非常に大きなデータ ストリームを受信した場合に、メモリ リソースの問題が発生します。

  • データベースにメディア リソースを格納する場合は、次の点を考慮してください。

    • メディア リソースであるバイナリ プロパティをデータ モデルに含めないようにしてください。 データ モデルで公開されるプロパティはすべて、応答フィードのエントリで返されます。

    • 大きなバイナリ ストリームのパフォーマンスを向上させるには、カスタム ストリーム クラスを作成してバイナリ データをデータベースに格納することをお勧めします。 このクラスは、GetWriteStream の実装によって返され、バイナリ データをチャンク単位でデータベースに送信します。 SQL Server データベースでは、バイナリ データが 1 MB を超える場合、FILESTREAM を使用してデータをデータベースにストリーミングすることをお勧めします。

    • データ サービスによって受信される大きなバイナリ ストリームを格納できるようにデータベースが設計されていることを確認してください。

    • クライアントが POST 要求を送信して、1 回の要求でメディア リソースと共にメディア リンク エントリを挿入する場合は、データ サービスによって新しいエンティティがデータベースに挿入される前に、GetWriteStream を呼び出してストリームを取得します。 ストリーミング プロバイダーは、このデータ サービスの動作を処理できるように実装する必要があります。 エンティティがデータベースに挿入されるまで、個別のデータ テーブルを使用してバイナリ データを格納するか、データ ストリームをファイルに格納することを検討してください。

  • DeleteStream メソッド、GetReadStream メソッド、または GetWriteStream メソッドを実装する場合は、メソッドのパラメーターとして指定される eTag 値および Content-Type 値を使用する必要があります。 IDataServiceStreamProvider プロバイダーの実装には、eTag ヘッダーまたは Content-Type ヘッダーを設定しないでください。

  • 既定では、クライアントはチャンクされた HTTP Transfer-Encoding を使用して、大きなバイナリ ストリームを送信します。 ASP.NET 開発サーバーはこの種類のエンコーディングをサポートしていないので、この Web サーバーを使用して大きなバイナリ ストリームを受け取る必要があるストリーミング データ サービスをホストすることはできません。ASP.NET 開発サーバーの詳細については、「Web Servers in Visual Web Developer」を参照してください。

バージョン管理の要件

ストリーミング プロバイダーには、次に示す OData プロトコルのバージョン管理の要件があります。

  • ストリーミング プロバイダーを使用するには、データ サービスでバージョン 2.0 以降の OData プロトコルがサポートされている必要があります。

  • 名前付きストリームをサポートするには、クライアントとデータ サービスの両方でバージョン 3.0 以降の OData プロトコルがサポートされている必要があります。

詳細については、「データ サービスのバージョン管理 (WCF Data Services)」を参照してください。

関連項目

概念

データ サービス プロバイダー (WCF Data Services)

カスタム データ サービス プロバイダー (WCF Data Services)

バイナリ データの操作 (WCF Data Services)