如何:访问流形式的二进制数据(Silverlight 客户端)

开放式数据协议 (OData) 使得数据服务能在源本身以外提供二进制数据。 这种二进制数据称为媒体资源,它与实体分离,但又与实体相关,此实体称为媒体链接项。有关更多信息,请参见使用二进制数据 (WCF Data Services)

本主题中的过程和示例演示如何添加对 Northwind 流示例数据服务的引用,并调用 GetReadStream 方法从 OData 服务以流形式检索二进制数据。 

应用程序访问的流数据服务是为了支持流而经过修改的特殊版本的 Northwind 示例数据服务。 有关更多信息,请参见流提供程序 (WCF Data Services)。 可以从 MSDN 代码库网站下载 Northwind 流数据服务示例。

备注

如果 Northwind 流数据服务的域不是本主题所示示例的域,则必须使用跨域策略文件启用跨域通信。有关更多信息,请参见 HTTP Communication and Security with Silverlight

添加对 Northwind 流数据服务示例的引用

  1. MSDN 代码库网站下载 Northwind 流数据服务示例,并按照示例自述文件中的说明在 IIS 上部署服务。

  2. 右击 Silverlight 项目,然后单击**“添加服务引用”**。 

  3. 在**“地址”文本框中,键入已部署的 Northwind 流数据服务的 URI,然后单击“转到”**。

  4. 在**“命名空间”文本框中,键入 NorthwindStreaming,然后单击“确定”**。

    这将在项目中添加一个新的代码文件,其中包含用于作为对象访问数据服务资源并与其交互的数据类。

示例

下面的示例来自一个可扩展应用程序标记语言 (XAML) 页的代码隐藏页,该 XAML 页是 Silverlight 的 StreamingClient 应用程序。 加载此页后,会根据返回所有员工的查询结果创建 DataServiceCollection<T>。 选择某个员工后,将调用 DataServiceContext 实例的 BeginGetReadStream 方法。 异步调用完成时,调用 OnGetReadStreamComplete 处理程序。 在此方法中,使用调度程序来调用 EndGetReadStream 方法,并且从 DataServiceStreamResponse 对象访问二进制流。

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 = _
            "https://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
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using StreamingClient.NorthwindStreaming;
using System.Data.Services.Client;
using System.IO;

namespace StreamingClient
{
    public partial class MainPage : UserControl
    {

        private NorthwindEntities context;
        private DataServiceCollection<Employees> trackedEmployees;
        private Employees currentEmployee;
        private BitmapImage imageSource;

        // Replace with the URI of your NorthwindStreaming service implementation.
        private string svcUri =
            "https://localhost/NorthwindStreaming/NorthwindStreaming.svc";

        public MainPage()
        {
            InitializeComponent();
        }


        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Instantiate the data service context.
            context = new NorthwindEntities(new Uri(svcUri));

            // Define a LINQ query for Employees.
            var query = from employees in context.Employees
                        select employees;

            try
            {
                // Create a new collection for binding all employees.
                trackedEmployees = new DataServiceCollection<Employees>();

                // Define a handler for the LoadCompleted event of the binding collection.
                trackedEmployees.LoadCompleted +=
                    new EventHandler<LoadCompletedEventArgs>(trackedEmployees_LoadCompleted);

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

            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private void trackedEmployees_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                // Load all pages of Orders before binding.
                if (trackedEmployees.Continuation != null)
                {
                    // 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)
                    {
                        MessageBox.Show("Data could not be returned from the data service.");
                    }

                    // Select the first employee in the collection.
                    employeesComboBox.SelectedIndex = 0;
                }
            }
            else
            {
                MessageBox.Show(string.Format("An error has occured: {0}", e.Error.Message));
            }
        }

        private void employeesComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Get the currently selected employee.
            currentEmployee =
                (Employees)this.employeesComboBox.SelectedItem;

            // Set the Accept header to the jpeg image content type.
            DataServiceRequestArgs 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, 
                    OnGetReadStreamComplete, context);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void OnGetReadStreamComplete(IAsyncResult result)
        {
            // Use the Dispatcher to ensure that the 
            // asynchronous call returns in the correct thread.
            Dispatcher.BeginInvoke(() =>
                {
                    // Get the original context back from the result.
                    context =
                        result.AsyncState as NorthwindEntities;

                    try
                    {
                        // Get the response from the returned context.
                        DataServiceStreamResponse response = 
                            context.EndGetReadStream(result);

                        using (MemoryStream imageStream =
                            new MemoryStream())
                        {
                            byte[] buffer = new byte[1000];
                            int count = 0;

                            // Read the returned stream into the new memory stream.
                            while (response.Stream.CanRead && (0 < (
                                count = response.Stream.Read(buffer, 0, buffer.Length))))
                            {
                                imageStream.Write(buffer, 0, count);
                            }

                            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;
                        }
                    }
                    catch (DataServiceRequestException ex)
                    {
                        MessageBox.Show(ex.InnerException.Message);
                    }
                    catch (Exception)
                    {
                        MessageBox.Show(
                            string.Format("The requested image for employee '{0}' is not valid.",
                            currentEmployee.LastName));
                    }
                }
            );
        }
    }
}

下面的 XAML 定义上例的页。

<UserControl x:Class="StreamingClient.MainPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://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>

请参阅

其他资源

WCF Data Services (Silverlight)

使用二进制数据 (WCF Data Services)