Proveedores de transmisión por secuencias (WCF Data Services)

Un servicio de datos puede exponer datos binarios de objetos grandes. Estos datos binarios pueden representar secuencias de vídeo y audio, imágenes, archivos de documento u otros tipos de medios binarios. Cuando una entidad del modelo de datos incluye una o más propiedades binarias, el servicio de datos devuelve estos datos binarios codificados en base 64 en la entrada de la fuente de respuesta. Dado que la carga y la serialización de datos binarios grandes de esta manera pueden afectar al rendimiento, Open Data Protocol (OData) define un mecanismo para recuperar datos binarios independientemente de la entidad a la que pertenezcan. Para ello, se separan los datos binarios de la entidad en uno o varios flujos de datos.

El protocolo OData admite los dos mecanismos siguientes para exponer datos binarios como flujos relacionados con una entidad:

  • Recurso multimedia/entrada de vínculo multimedia

    El protocolo de publicación Atom (AtomPub) define un mecanismo para asociar datos binarios como un recurso multimedia con una entrada de una fuente de datos, que se denomina la entrada de vínculo multimedia. Solo puede haber un recurso multimedia definido para una entrada de vínculo multimedia determinada. Un recurso multimedia puede ser considerado como el flujo predeterminado de una entidad. OData hereda este comportamiento de transmisión de datos de AtomPub.

  • Flujo de recursos con nombre

    A partir de la versión 3 de OData, una entidad puede tener varios flujos de recursos relacionados, a los que se tiene acceso por nombre. Este mecanismo no depende de AtomPub, por lo que es posible que una entidad tenga flujos de recursos con nombre y no sea una entrada de vínculo multimedia. También es posible que una entrada de vínculo multimedia tenga flujos con nombre. Para obtener más información, vea la entrada de blog relacionada con los flujos de recursos con nombre.

Con Servicios de datos de Microsoft WCF, defina flujos de recursos binarios implementando proveedores de transmisión de datos. Las implementaciones del proveedor de transmisión por secuencias proporcionan al servicio de datos los flujos asociados a una entidad concreta como objetos Stream.

La configuración de un servicio de datos para que admita la transmisión por flujos de datos binarios requiere los siguientes pasos:

  1. Atribuir la entidad en el modelo de datos que tiene flujos de recursos relacionados. Cada proveedor de datos tiene sus propios requisitos y cada tipo de flujo de recursos binarios se define en el modelo de datos mediante un mecanismo diferente.

  2. Implemente las siguientes interfaces de proveedor de flujos:

  3. Defina un servicio de datos que implemente la interfaz IServiceProvider. El servicio de datos usa la implementación del método GetService para acceder a la implementación del proveedor de transmisión de datos por secuencias. Este método devuelve la implementación del proveedor de transmisión por secuencias adecuado.

  4. Habilite flujos de mensajes grandes en la configuración de la aplicación web.

  5. Habilite el acceso a los recursos binarios en el servidor o en un origen de datos.

Los ejemplos de este tema se basan en un servicio de fotografías de transmisión por secuencias de ejemplo, que se describe con todo detalle en la entrada del blog relacionado con la parte 1 de la implementación de un proveedor de transmisión por secuencias de la serie de proveedores de transmisión por secuencias de servicios de datos. El código fuente de este servicio de ejemplo está disponible en la página de ejemplo del servicio de datos de fotografía de transmisión por secuencias de la galería de código de MSDN.

Definir los flujos de recursos en el modelo de datos

La manera en la que un flujo de recursos binarios se define en el modelo de datos depende de si el flujo es un recurso multimedia o un flujo de recursos con nombre, así como del proveedor del origen de datos que se va a utilizar. En el ejemplo siguiente se muestra la definición de un recurso multimedia en los metadatos devueltos por el servicio de datos, donde PhotoInfo es una entrada de vínculo multimedia que también tiene definido un flujo de recursos con nombre (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>

Proveedor de Entity Framework

Al utilizar el proveedor de Entity Framework, define un flujo de recursos binarios en el propio modelo de datos de una de las siguientes maneras, dependiendo del tipo de flujo:

  • Flujo de recursos multimedia:

    Para indicar que una entidad es una entrada de vínculo multimedia que tiene un recurso multimedia asociado, agregue el atributo HasStream a la definición del tipo de entidad en el modelo conceptual. También debe agregar una referencia al espacio de nombres xmlns:m=https://schemas.microsoft.com/ado/2007/08/dataservices/metadata a la entrada de vínculo multimedia o a uno de sus elementos primarios en el modelo de datos.

  • Flujo de recursos con nombre:

    Un flujo con nombre que pertenece a una entrada de vínculo multimedia se define como una propiedad de tipo Stream en el modelo conceptual.

    Importante

    Entity Data Model (EDM) admite el tipo de datos Stream, a partir de la versión 2.2.Sin embargo, en .NET Framework 4, Entity Framework no admite esta versión del EDM.Como solución alternativa, puede definir en su lugar un flujo de recursos con nombre en el modelo de datos aplicando NamedStreamAttribute a la clase en la capa de objeto del modelo de datos que representa la entidad.En este atributo, el parámetro name es el nombre del flujo.Recomendamos agregar este atributo a la clase de entidad creando una definición de clase parcial que se mantiene en un archivo de código independiente; de lo contrario, esta personalización se sobrescribirá cuando Entity Framework vuelva a generar las clases de datos de la entidad.Como con el proveedor de reflexión, el servicio de datos genera una propiedad del name proporcionado de tipo Stream en el modelo de datos.

Para obtener un ejemplo de exposición de un recurso multimedia usando el proveedor Entity Framework, vea la entrada del blog relacionado con la parte 1 de la implementación de un proveedor de transmisión por flujos de la serie de proveedores de transmisión por flujos de servicios de datos.

Proveedor de reflexión

Al utilizar el proveedor de reflexión, identifica que un flujo de recursos binarios pertenece a un tipo de entidad aplicando los atributos de una de las siguientes maneras a la clase que es el tipo de entidad, dependiendo de la clase de flujo:

  • Flujo de recursos multimedia:

    Aplique HasStreamAttribute para definir un flujo de recursos multimedia (predeterminado) que pertenece al tipo, que es una entrada de vínculo multimedia.

  • Flujo de recursos con nombre:

    Aplique NamedStreamAttribute para definir un flujo de recursos con nombre que pertenece el tipo de entidad, en el que el parámetro name proporcionado es el nombre del flujo.

Proveedor de servicios de datos personalizados

Cuando se usan proveedores de servicios personalizados, implemente la interfaz IDataServiceMetadataProvider para definir los metadatos del servicio de datos. Para obtener más información, vea Proveedores de servicios de datos personalizados (WCF Data Services). Indica que un flujo de recursos binarios pertenece a un ResourceType de una de las siguientes maneras:

Implementar las interfaces de proveedor de flujos

Para crear un servicio de datos que admita flujos de datos binarios, debe implementar al menos la interfaz IDataServiceStreamProvider. Esta implementación permite al servicio de datos devolver al cliente datos binarios como un flujo y utilizar los datos binarios como un flujo enviado desde el cliente. Para admitir flujos con nombre, debe implementar también la interfaz IDataServiceStreamProvider2. El servicio de datos crea una instancia de la interfaz apropiada cuando sea necesario para tener acceso a datos binarios como un flujo.

IDataServiceStreamProvider

La interfaz IDataServiceStreamProvider especifica los siguientes miembros:

Nombre del miembro

Descripción

DeleteStream

El servicio de datos invoca este método para eliminar tanto el recurso multimedia correspondiente como cualquier flujo con nombre cuando se elimina su entrada de vínculo multimedia. Cuando se implementa IDataServiceStreamProvider, este método contiene el código que elimina todos los datos binarios transmitidos asociados a la entrada de vínculo multimedia proporcionada.

GetReadStream

El servicio de datos invoca este método para devolver un recurso multimedia como un flujo. Cuando se implementa IDataServiceStreamProvider, este método contiene el código que proporciona un flujo que el servicio de datos utiliza para devolver el recurso multimedia que está asociado a la entrada de vínculo multimedia proporcionada.

GetReadStreamUri

El servicio de datos invoca este método para devolver el URI que se utiliza para solicitar el recurso multimedia de la entrada de vínculo multimedia. Este valor se usa para crear el atributo src en el elemento de contenido de la entrada de vínculo multimedia que se utiliza para solicitar el flujo de datos. Cuando este método devuelve null, el servicio de datos automáticamente determina el URI. Use este método cuando deba proporcionar clientes con acceso directo a datos binarios sin usar el proveedor de flujos.

GetStreamContentType

El servicio de datos invoca este método para devolver el valor Content-Type del recurso multimedia asociado con la entrada de vínculo multimedia especificada.

GetStreamETag

El servicio de datos invoca este método para devolver el objeto eTag del flujo de datos que está asociado con la entidad especificada. Este método se utiliza cuando se administra la simultaneidad de los datos binarios. Cuando este método devuelve null , el servicio de datos no realiza el seguimiento de la simultaneidad.

GetWriteStream

El servicio de datos invoca este método para obtener el flujo que se utiliza cuando se recibe el flujo enviado desde el cliente. Cuando implemente la interfaz IDataServiceStreamProvider, debe devolver un flujo grabable en el que el servicio de datos pueda escribir los datos del flujo recibidos.

ResolveType

Devuelve un nombre de tipo calificado con el espacio de nombres que representa el tipo que el motor en tiempo de ejecución del servicio de datos debe crear para la entrada de vínculo multimedia asociada al flujo de datos del recurso multimedia que se está insertando.

IDataServiceStreamProvider2

La interfaz IDataServiceStreamProvider2 especifica los siguientes miembros, que sobrecargan los miembros de IDataServiceStreamProvider para tomar un parámetro ResourceProperty que es un flujo de recursos con nombre:

Nombre del miembro

Descripción

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

El servicio de datos invoca este método para devolver un flujo con nombre. Cuando se implementa IDataServiceStreamProvider2, este método contiene el código que proporciona un flujo que el servicio de datos utiliza para devolver el flujo con nombre solicitado que está asociado a la entrada de vínculo multimedia proporcionada.

GetReadStreamUri(Object, ResourceProperty, DataServiceOperationContext)

El servicio de datos invoca este método para devolver el URI que se utiliza para solicitar un flujo con nombre específico para la entrada de vínculo multimedia. Este valor se usa para crear el elemento atom:link que se utiliza para solicitar el flujo con nombre. Cuando este método devuelve null, el servicio de datos automáticamente determina el URI. Use este método cuando deba proporcionar clientes con acceso directo a datos binarios sin usar el proveedor de flujos.

GetStreamContentType(Object, ResourceProperty, DataServiceOperationContext)

El servicio de datos invoca este método para devolver el valor Content-Type de un flujo con nombre específico asociado a la entrada de vínculo multimedia especificada.

GetStreamETag(Object, ResourceProperty, DataServiceOperationContext)

El servicio de datos invoca este método para devolver el objeto eTag de un flujo con nombre específico asociado a la entidad especificada. Este método se utiliza cuando se administra la simultaneidad de los datos binarios. Cuando este método devuelve null , el servicio de datos no realiza el seguimiento de la simultaneidad.

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

El servicio de datos invoca este método para obtener el flujo que se utiliza cuando se recibe un flujo con nombre enviado desde el cliente. Cuando implemente la interfaz IDataServiceStreamProvider2, debe devolver un flujo grabable en el que el servicio de datos pueda escribir los datos del flujo recibidos.

Crear el servicio de transmisión de datos por flujos

Para proporcionar al motor de tiempo de ejecución de Servicios de datos de Microsoft WCF acceso a las implementaciones de interfaz IDataServiceStreamProvider y IDataServiceStreamProvider2, el servicio de datos que cree también debe implementar la interfaz IServiceProvider. En el ejemplo siguiente se muestra cómo implementar el método GetService para devolver una instancia de la clase PhotoServiceStreamProvider que implemente IDataServiceStreamProvider y IDataServiceStreamProvider2.

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;
    }
}

Para obtener información general sobre cómo crear un servicio de datos, vea Configurar el servicio de datos (WCF Data Services).

Habilitar flujos binarios grandes en el entorno de hospedaje

Cuando cree un servicio de datos en una aplicación web de ASP.NET, se usa Windows Communication Foundation (WCF) para proporcionar la implementación del protocolo HTTP. De forma predeterminada, WCF limita el tamaño de los mensajes HTTP a solo 65K bytes. Para poder transmitir datos binarios grandes por secuencias al servicio de datos y desde él, debe configurar también la aplicación web para habilitar archivos binarios grandes y utilizar secuencias para la transferencia. Para ello, en el elemento <configuration /> del archivo Web.config de la aplicación agregue lo siguiente:

 <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>

Nota

Debe usar un modo de transferencia del campo TransferMode.Streamed para asegurarse de que los datos binarios en los mensajes de solicitud y respuesta se transfieran y que WCF no los almacene en búfer.

Para obtener más información, vea Streaming Message Transfer y Transport Quotas.

De forma predeterminada, Internet Information Services (IIS) también limita el tamaño de las respuestas a 4 MB. Para habilitar el servicio de datos con el fin de recibir flujos mayores que 4 MB cuando se ejecute en IIS, también debe establecer el atributo maxRequestLength del elemento httpRuntime Element de la sección de configuración de <system.web /> como se muestra en el siguiente ejemplo:

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

Usar flujos de datos en una aplicación cliente

Puede tener acceso directamente a un flujo de datos binarios utilizando uno de los siguientes URI:

  • Flujo de recursos multimedia:

    https://localhost/PhotoService/PhotoData.svc/PhotoInfo(1)/$value
    
  • Flujo de recursos con nombre:

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

La biblioteca cliente de Servicios de datos de Microsoft WCF le permite recuperar y actualizar estos recursos expuestos como flujos binarios en el cliente. Para obtener más información, vea Trabajar con datos binarios (Servicios de datos de WCF).

Consideraciones para trabajar con un proveedor de transmisión por secuencias

A continuación se enumeran algunas de las consideraciones que debe tener en cuenta al implementar un proveedor de transmisiones por secuencias y al tener acceso a los recursos multimedia de un servicio de datos.

  • Debe implementar la interfaz IDataServiceStreamProvider al admitir flujos de recursos multimedia o de recursos con nombre. Para admitir flujos de recursos con nombre, debe implementar también la interfaz IDataServiceStreamProvider2.

  • Al definir un flujo de recursos con nombre que pertenece a una entrada de vínculo multimedia, la entidad definida en el modelo de datos no debe incluir una propiedad con el mismo nombre que el flujo.

  • Los recursos multimedia no admiten solicitudes MERGE. Utilice una solicitud PUT para cambiar el recurso multimedia de una entidad existente.

  • Una solicitud POST no se puede utilizar para crear una entrada de vínculo multimedia. En su lugar, debe emitir una solicitud POST para crear un nuevo recurso multimedia y el servicio de datos creará una entrada de vínculo multimedia con los valores predeterminados. Una solicitud MERGE o PUT posterior puede actualizar esta nueva entidad. También puede considerar la opción de almacenar en memoria caché la entidad y realizar actualizaciones en el contenedor de elementos eliminados, como establecer el valor de propiedad en el valor del encabezado Slug en la solicitud POST.

  • Cuando se recibe una solicitud POST, el servicio de datos llama a GetWriteStream para crear el recurso multimedia antes de llamar a SaveChanges para crear la entrada de vínculo multimedia.

  • Una implementación de GetWriteStream no debe devolver un objeto MemoryStream. Cuando se utiliza este tipo de flujo, se producirán problemas de recursos de memoria cuando el servicio reciba flujos de datos muy grandes.

  • A continuación se enumeran algunas de las consideraciones que debe tener en cuenta al almacenar recursos multimedia en una base de datos:

    • En el modelo de datos no debe incluirse una propiedad binaria que sea un recurso multimedia. Todas las propiedades expuestas en un modelo de datos se devuelven en la entrada de una fuente de respuesta.

    • Para mejorar el rendimiento con un flujo binario grande, recomendamos crear una clase de flujo personalizado para almacenar datos binarios en la base de datos. La implementación de GetWriteStream devuelve esta clase y envía los datos binarios a la base de datos en fragmentos. En el caso de una base de datos de SQL Server, se recomienda usar un objeto FILESTREAM para transmitir los datos por secuencias a la base de datos cuando los datos binarios ocupen más de 1 MB.

    • Asegúrese de que la base de datos esté diseñada para almacenar los flujos binarios grandes que vaya a recibir el servicio de datos.

    • Cuando un cliente envía a una solicitud POST para insertar una entrada de vínculo multimedia con un recurso multimedia en una solicitud única, se llama a GetWriteStream para obtener el flujo antes de que el servicio de datos inserte la nueva entidad en la base de datos. Una implementación del proveedor de transmisiones por secuencias debe ser capaz de controlar este comportamiento del servicio de datos. Considere la opción de usar una tabla de datos independiente para almacenar los datos binarios o almacenar el flujo de datos en un archivo hasta que la entidad se haya insertado en la base de datos.

  • Cuando implemente los métodos DeleteStream, GetWriteStream o GetReadStream, debe utilizar el objeto eTag y los valores Content-Type y que se proporcionan como parámetros de método. No establezca el objeto eTag ni los encabezados Content-Type en la implementación del proveedor IDataServiceStreamProvider.

  • De forma predeterminada, el cliente envía secuencias binarias grandes mediante codificación de transferencia HTTP fragmentada. Dado que el servicio de desarrollo de ASP.NET no admite este tipo de codificación, no podrá usar este servidor web para hospedar los servicios de transmisión de datos por secuencias que deban aceptar flujos binarios grandes. Para obtener más información sobre el servidor de desarrollo de ASP.NET, vea Web Servers in Visual Web Developer.

Requisitos de control de versiones

El proveedor de transmisión por secuencias tiene los siguientes requisitos de control de versiones de OData:

  • El proveedor de transmisión por secuencias requiere que el servicio de datos admita la versión 2.0 del protocolo de OData y versiones posteriores.

  • La compatibilidad con flujos con nombre requiere que tanto el cliente como el servicio de datos admitan la versión 3.0 del protocolo de OData y versiones posteriores.

Para obtener más información, vea Control de versiones del servicio de datos (Servicios de datos de Microsoft WCF).

Vea también

Conceptos

Proveedores de servicios de datos (WCF Data Services)

Proveedores de servicios de datos personalizados (WCF Data Services)

Trabajar con datos binarios (Servicios de datos de WCF)