資料流處理提供者 (WCF Data Services)

資料服務可以公開大型物件二進位資料。 這項二進位資料可能代表視訊和音訊資料流、影像、文件檔案,或其他類型的二進位媒體。 當資料模型中的實體包含一個或多個二進位屬性時,資料服務會在回應摘要的項目內,傳回這個 base-64 編碼形式的二進位資料。 因為以這個方法載入及序列化大型二進位資料會影響效能,所以 Open Data Protocol (OData) 會定義一個機制來獨立擷取二進位資料,而與其所屬的實體無關。 只要將實體中的二進位資料分成一個或多個資料流就可以完成這項處理。

OData 通訊協定支援下列兩種機制來公開二進位資料做為與實體相關的資料流:

  • 媒體資源/媒體連結項目

    Atom 發行通訊協定 (AtomPub) 會定義一個機制,讓二進位資料當做「媒體資源」(Media Resource) 與資料摘要中的項目 (稱為「媒體連結項目」(Media Link Entry)) 產生關聯。 針對給定的媒體連結項目,可能只能定義一個媒體資源。 媒體資源可以視為實體的預設資料流。 OData 會從 AtomPub 繼承這個資料流行為。

  • 具名的資源資料流

    從 OData 第 3 版開始,一個實體可以有多個透過名稱存取的相關資源資料流。 這個機制與 AtomPub 無關,因此,實體可能會有具名的資源資料流,而不是媒體連結項目。 媒體連結項目也可能會有具名的資料流。 如需詳細資訊,請參閱 文章具名的資源資料流

透過 WCF Data Services,您可以實作資料流處理資料提供者來定義二進位資源資料流。 資料流處理提供者實作會為資料服務提供與特定實體相關聯的資料流當做 Stream 物件。

設定資料服務來支援二進位資料的資料流處理需要進行以下步驟:

  1. 將實體歸類在擁有相關資源資料流的資料模型中。 每個資料提供者都有自己的需求,而且每種二進位資源資料流都是透過不同的機制,在資料模型中定義。

  2. 實作下列資料流提供者介面:

  3. 定義資料服務來實作 IServiceProvider 介面。 此資料服務會使用 GetService 實作來存取資料流處理資料提供者實作。 這個方法會傳回適當的資料流處理提供者實作。

  4. 在 Web 應用程式組態中啟用大型訊息資料流。

  5. 啟用伺服器上或資料來源中之二進位資源的存取權。

本主題中的範例是以資料流處理相片服務範例為基礎 (資料服務資料流處理提供者系列:實作資料流處理提供者 (第 1 部分) 文章中進行深度探討)。 您可以在 MSDN Code Gallery 的資料流處理相片資料服務範例頁面上找到此範例服務的原始程式碼。

在資料模型中定義資源資料流

在資料模型中定義二進位資源資料流的方式取決於此資料流是媒體資源還是具名的資源資料流,以及所使用的資料來源提供者。 以下範例顯示資料服務所傳回之中繼資料中的媒體資源定義,其中 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 類型的屬性。

    重要

    從 實體資料模型 (EDM) 2.2 版開始,支援 Stream 資料類型。不過在 .NET Framework 4 中,Entity Framework 不支援這個版本的 EDM。您可以透過將 NamedStreamAttribute 套用至表示實體之資料模型物件層中的類別,來定義資料模型中的具名資源資料流,便可解決這個問題。在此屬性中,name 參數是資料流的名稱。建議您建立在個別程式碼檔案中維護的部分類別定義,以便將此屬性加入至實體類別,否則,當 Entity Framework 重新產生實體資料類別時,這個自訂項目會遭到覆寫。如同反映提供者,資料服務會在資料模型中產生 Stream 類型所提供之 name 的屬性。

如需使用 Entity Framework 提供者公開媒體資源的詳細資訊,請參閱文章資料服務資料流處理提供者系列:實作資料流處理提供者 (第 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 執行階段提供 IDataServiceStreamProviderIDataServiceStreamProvider2 實作的存取權,您所建立的資料服務也必須實作 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 訊息大小限制為只有 65 KB。 為了要能夠與資料服務之間來回進行大型二進位資料的資料流處理,您也必須設定 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 TransferTransport Quotas

根據預設,Internet Information Services (IIS) 也會將要求的大小限制為 4MB。 若要讓資料服務在 IIS 上執行時接收大於 4MB 的資料流,您也必須在 <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 要求,將包含媒體資源的媒體連結項目插入單一要求時,將會呼叫 GetWriteStream 來取得資料流,然後資料服務才會將新的實體插入資料庫中。 資料流處理提供者實作必須能夠處理這個資料服務行為。 請考慮使用個別的資料表來儲存二進位資料或是將資料流儲存在檔案中,直到實體已經插入資料庫為止。

  • 當您實作 DeleteStreamGetReadStreamGetWriteStream 方法時,您必須使用當做方法參數提供的 eTag 和 Content-Type 值。 請勿在 IDataServiceStreamProvider 提供者實作中設定 eTag 或 Content-Type 標頭。

  • 根據預設,用戶端會使用區塊式 HTTP Transfer-Encoding 來傳送大型二進位資料流。 因為 ASP.NET 程式開發伺服器不支援這種編碼方式,所以您不能使用這個網頁伺服器來裝載必須接受大型二進位資料流的資料流處理資料服務。如需 ASP.NET 程式開發伺服器的詳細資訊,請參閱 Web Servers in Visual Web Developer

版本控制需求

資料流處理提供者具有下列 OData 通訊協定版本控制需求:

  • 資料流處理提供者要求資料服務支援 2.0 版的 OData 通訊協定和更新版本。

  • 對於具名資料流的支援,需要用戶端與資料服務都支援 OData 通訊協定 3.0 版和更新版本。

如需詳細資訊,請參閱資料服務版本控制 (WCF Data Services)

請參閱

概念

資料服務提供者 (WCF Data Services)

自訂資料服務提供者 (WCF Data Services)

使用二進位資料 (WCF Data Services)