How to: Access Binary Data as a Stream (WCF Data Services/Silverlight)

Open Data Protocol (OData) enables a data service to make binary data available outside of the feed itself. This binary data, called a media resource, is separate from but related to an entity, which is called a media link entry. For more information, see Working with Binary Data (WCF Data Services).

The procedure and examples in this topic show you how to add a reference to the Northwind streaming sample data service and call the GetReadStream(Object) method to retrieve binary data as a stream from an OData service. 

The streaming data service accessed by the application is a special version of the Northwind sample data service that has been modified to support streaming. For more information see Streaming Provider (WCF Data Services). The Northwind streaming data service sample can be downloaded from the MSDN Code Gallery Web site.

Note Note:

When the domain of the Northwind streaming data service is different from the domain of the sample shown in this topic, you must enable cross-domain communication by using a cross-domain policy file. For more information, see HTTP Communication and Security with Silverlight.

To add a reference to the Northwind streaming data service sample

  1. Download the Northwind streaming data service sample from the MSDN Code Gallery Web site and follow the instructions in the sample readme file to deploy the service on IIS.

  2. Right-click the Silverlight project and click Add Service Reference

  3. In the Address text box, type the URI for the deployed Northwind streaming data service and then click Go.

  4. In the Namespace text box, type NorthwindStreaming, and then click OK.

    This adds a new code file to the project, which contains the data classes that are used to access and interact with data service resources as objects.

The following example is from the code-behind page for an Extensible Application Markup Language (XAML) page that is the StreamingClient application for Silverlight. When the page is loaded, a DataServiceCollection(Of T) is created based on the result of a query that returns all employees. When an employee is selected, the BeginGetReadStream method is called on the DataServiceContext instance. When the asynchronous call completes, the OnGetReadStreamComplete handler is called. In this method, the dispatcher is used to invoke the EndGetReadStream method and the binary stream is accessed from the DataServiceStreamResponse object. 


Imports System
Imports System.Linq
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.Windows.Media.Imaging
Imports StreamingClient.NorthwindStreaming
Imports System.Data.Services.Client
Imports System.IO
Partial Public Class MainPage
    Inherits UserControl

    Private context As NorthwindEntities
    Private trackedEmployees As DataServiceCollection(Of Employees)
    Private currentEmployee As Employees
    Private imageSource As BitmapImage
    Private currentResult As IAsyncResult

    ' Replace with the URI of your NorthwindStreaming service implementation.
    Private svcUri As String = _
            "http://localhost/NorthwindStreaming/NorthwindStreaming.svc"

    Public Sub New()
        InitializeComponent()
    End Sub
    Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Instantiate the data service context.
        context = New NorthwindEntities(New Uri(svcUri))

        ' Define a LINQ query for Employees.
        Dim query = From employees In context.Employees _
                    Select employees
        Try
            ' Create a new collection for binding all employees.
            trackedEmployees = New DataServiceCollection(Of Employees)()

            ' Define a handler for the LoadCompleted event of the binding collection.
            AddHandler trackedEmployees.LoadCompleted, _
               AddressOf trackedEmployees_LoadCompleted

            ' Execute the query asynchronously and 
            ' load the results into the collection.
            trackedEmployees.LoadAsync(query)

        Catch ex As InvalidOperationException
            MessageBox.Show(ex.Message)
        End Try
    End Sub
    Private Sub trackedEmployees_LoadCompleted(ByVal sender As Object, ByVal e As LoadCompletedEventArgs)
        If e.Error Is Nothing Then
            ' Load all pages of Orders before binding.
            If trackedEmployees.Continuation IsNot Nothing Then

                ' Load the next page of results.
                trackedEmployees.LoadNextPartialSetAsync()
            Else
                ' Bind the root StackPanel element to the collection
                ' related object binding paths are defined in the XAML.
                LayoutRoot.DataContext = trackedEmployees

                If trackedEmployees.Count = 0 Then
                    MessageBox.Show("Data could not be returned from the data service.")
                End If

                ' Select the first employee in the collection.
                employeesComboBox.SelectedIndex = 0
            End If
                Else
                MessageBox.Show(String.Format("An error has occured: {0}", e.Error.Message))
        End If
    End Sub
    Private Sub employeesComboBox_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)

        ' Define the method to call when the asynchronous method completes.
        Dim callback As AsyncCallback = AddressOf OnGetReadStreamComplete

        ' Get the currently selected employee.
        currentEmployee = _
            CType(Me.employeesComboBox.SelectedItem, Employees)

        ' Set the Accept header to the jpeg image content type.
        Dim requestArgs = New DataServiceRequestArgs()
        requestArgs.AcceptContentType = "image/jpeg"

        Try
            ' Start to get the read stream for the media resource for the 
            ' currently selected media link entry.    
            context.BeginGetReadStream(currentEmployee, requestArgs, _
                callback, context)

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub
    Private Sub OnGetReadStreamComplete(ByVal result As IAsyncResult)
        ' Persist the context from the result.
        currentResult = result

        ' Use the Dispatcher to ensure that the 
        ' asynchronous call returns in the correct thread.
        Dispatcher.BeginInvoke(AddressOf OnGetReadStreamCompleteByDispatcher)
    End Sub
    Private Sub OnGetReadStreamCompleteByDispatcher()

        ' Use the Dispatcher to ensure that the 
        ' asynchronous call returns in the correct thread.
        ' Get the original context back from the result.
        context = CType(currentResult.AsyncState, NorthwindEntities)

        Try
            ' Get the response from the returned context.
            Dim response =
                context.EndGetReadStream(currentResult)

            Using imageStream As MemoryStream = _
                New MemoryStream()

                Dim buffer = New Byte(1000) {}
                Dim count = 0

                ' Read the returned stream into the new memory stream.
                If response.Stream.CanRead Then
                    Do
                        count = response.Stream.Read(buffer, 0, buffer.Length)
                        imageStream.Write(buffer, 0, count)
                    Loop While 0 < count
                End If

                imageStream.Position = 0

                ' Use the returned bitmap stream to create a bitmap image that is 
                ' the source of the image control.
                imageSource = New BitmapImage()
                imageSource.SetSource(imageStream)
                employeeImage.Source = imageSource
            End Using

        Catch ex As DataServiceRequestException
            MessageBox.Show(ex.InnerException.Message)                
        Catch ex As Exception
            MessageBox.Show( _
                String.Format("The requested image for employee '{0}' is not valid.", _
                currentEmployee.LastName))
        End Try
    End Sub    
End Class


The following XAML defines the page for the previous example.


<UserControl x:Class="StreamingClient.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Height="300" Width="400" Loaded="Window_Loaded">
    <Grid Name="LayoutRoot" >
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Width="Auto" VerticalAlignment="Bottom" Height="50" Margin="0,0,0,250">
            <ComboBox Height="23" Name="employeesComboBox" Margin="50,12,0,12" Width="200" DisplayMemberPath="LastName" ItemsSource="{Binding}" SelectionChanged="employeesComboBox_SelectionChanged" />
        </StackPanel>
        <Image Margin="12,76,12,26" Name="employeeImage" Width="350" Stretch="Fill"/>
    </Grid>
</UserControl>


Community Additions

ADD
Show: