{"id":1153,"date":"2010-09-08T18:19:23","date_gmt":"2010-09-08T18:19:23","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2010\/09\/08\/data-services-streaming-provider-series-part-2-accessing-a-media-resource-stream-from-the-client\/"},"modified":"2024-02-16T13:30:39","modified_gmt":"2024-02-16T20:30:39","slug":"data-services-streaming-provider-series-part-2-accessing-a-media-resource-stream-from-the-client","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/data-services-streaming-provider-series-part-2-accessing-a-media-resource-stream-from-the-client\/","title":{"rendered":"Data Services Streaming Provider Series-Part 2: Accessing a Media Resource Stream from the Client"},"content":{"rendered":"<p>In this second post in the series on implementing a streaming data provider, we show how to use the WCF Data Services client library to access binary data exposed by an Open Data Protocol (OData) feed, as well as has how to upload binary data to the data service. For more information on the streaming provider, see the first blog post in this series: <font color=\"#ff0000\"><a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkID=198989\">Implementing a Streaming Provider<\/a><\/font>.<\/p>\n<h3>PhotoData Sample Client Application<\/h3>\n<p>In the <a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkID=198989\">previous post<\/a>, we showed how to implement <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.providers.idataservicestreamprovider\">IDataServiceStreamProvider<\/a> to create a data service that uses OData to store and retrieve binary image files, the <em>media resource<\/em> (MR) in OData terms, along with metadata about the photos, the <em>media link entry<\/em> (MLE) in OData terms. The Visual Studio solution for this sample data service, which is published to <a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkId=198988\">this MSDN Code Gallery page<\/a>, also contains a client application project. This client, which consumes feeds from the PhotoData service, accesses and displays image files stored by the data service. Creating a client application that can display photos from and send photos to our PhotoData sample data service requires the following basic steps:<\/p>\n<ol>\n<li>Create the client project and add a reference to the data service. <\/li>\n<li>Create the UI elements to display the MLE and MR data for the photo. <\/li>\n<li>Request a data feed from the service, get the URI of the MR for a specific MLE, and then use this URI to create an image based on the MR. <\/li>\n<li>When we are adding a new photo, create a new MLE object on the client, set any properties, and add the object to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext\">DataServiceContext<\/a>. <\/li>\n<li>Read an image from the local computer into a stream, pass the stream and the object to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.setsavestream\">SetSaveStream<\/a> method, and then call <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.savechanges\">SaveChanges<\/a>. <\/li>\n<\/ol>\n<p>As you may recall, the PhotoData sample data service exposes a single <strong>PhotoInfo<\/strong> entity (an MLE) which has a related image file (the MR). The <strong>HasStream<\/strong> attribute applied to the <strong>PhotoInfo<\/strong> entity tells the client that it is an MLE, as you can see in the <strong>PhotoInfo<\/strong> entity metadata returned by the data service:     <br \/><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/09\/4188.image_6A48D603.png\" \/><\/p>\n<p>Now, let\u2019s get started on creating the client application. <\/p>\n<h3>Creating the WPF Client Application<\/h3>\n<p>Our client application is a Windows Presentation Foundation (WPF) application. This enables us to use data binding of <strong>PhotoInfo<\/strong> objects to UI elements. <\/p>\n<p>First let\u2019s create the WPF client application (I won\u2019t go into too much detail here\u2026you can review the XAML that defines these windows in the client project included with the <a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkId=198988\">sample PhotoData streaming data service<\/a>):<\/p>\n<ol>\n<li>Create the WPF project. <\/li>\n<li>Use the <strong>Add Service Reference<\/strong> dialog in Visual Studio to add a reference to the PhotoData service that we implemented in the <a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkID=198989\">previous post<\/a>. <\/li>\n<li>The <strong>PhotoWindow<\/strong> displays the <strong>FileName<\/strong> property of the PhotoInfo objects materialized from the data feed in the <strong>photoComboBox<\/strong>:       \n<blockquote>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/09\/2844.image_thumb_52BFD925.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/09\/2844.image_thumb_52BFD925.png\" width=\"475\" height=\"380\" \/><\/a> <\/p>\n<\/blockquote>\n<p> When one of the <strong>PhotoInfo<\/strong> objects is selected, by file name, from the <strong>photoComboBox<\/strong>, the related image MR is requested from the data service and displayed as an image in the page. <\/li>\n<li>The <strong>PhotoDetailsWindow<\/strong> displays the properties of the selected <strong>PhotoInfo<\/strong> object:       \n<blockquote>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/09\/8206.image_thumb_37A70A17.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/09\/8206.image_thumb_37A70A17.png\" width=\"476\" height=\"332\" \/><\/a> <\/p>\n<\/blockquote>\n<p> This window is displayed when you click <strong>Add Photo<\/strong> or<strong> Photo Details<\/strong> in the <strong>PhotoWindow<\/strong>. <\/li>\n<\/ol>\n<p>Now let\u2019s see how the MLE and MR data from the data service is propagated into these UI elements. <\/p>\n<h3>Querying the Data Service and Displaying the Streamed Data<\/h3>\n<p>The following steps are required to query the PhotoData service for the data feed and get images for a specific <strong>PhotoInfo<\/strong> object.<\/p>\n<ol>\n<li>Declare the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext\">DataServiceContext<\/a> used to access the data service and the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecollection\">DataServiceCollection<\/a> used for data binding:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">private PhotoDataContainer context;            <br \/>private DataServiceCollection&lt;PhotoInfo&gt; trackedPhotos;             <br \/>private PhotoInfo currentPhoto; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Get the service URI from the settings file.            <br \/>private Uri svcUri =             <br \/>&#160;&#160;&#160; new Uri(Properties.Settings.Default.svcUri);<\/font><\/p>\n<\/blockquote>\n<p> Note that the data service URI is stored in the app.config file.       <\/li>\n<li>When the <strong>PhotoWindow<\/strong> is loaded, execute the query that loads the binding collection with objects from the <strong>PhotoInfo<\/strong> feed returned by the data service:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Define a query that returns a feed with all PhotoInfo objects.            <br \/>var query = context.PhotoInfo; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Create a new collection for binding based on the executed query.            <br \/>trackedPhotos = new DataServiceCollection&lt;PhotoInfo&gt;(query); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Load all pages of the response into the binding collection.            <br \/>while (trackedPhotos.Continuation != null)             <br \/>{             <br \/>&#160;&#160;&#160; trackedPhotos.Load(             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; context.Execute&lt;PhotoInfo&gt;(trackedPhotos.Continuation.NextLinkUri));             <br \/>}<\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\"><\/font><\/p>\n<\/blockquote>\n<\/li>\n<li>When the user selects a file name from the <strong>photoComboBox<\/strong>, call the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.getreadstreamuri\">GetReadStreamUri<\/a> method to request the MR from the data service, as follows:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Use the ReadStreamUri of the Media Resource for selected PhotoInfo object            <br \/>\/\/ as the URI source of a new bitmap image.             <br \/>photoImage.Source = new BitmapImage(context.GetReadStreamUri(currentPhoto));<\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\"><\/font><\/p>\n<\/blockquote>\n<p>The returned URI is used to create the image on the client that is displayed in the UI.        <\/p>\n<blockquote style=\"margin-right: 0px\">\n<p><strong>Note:<\/strong> The URI of the MR works very well for creating an image on the client. However, when you need the MR returned as a binary stream instead of just the URI, you must instead use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.getreadstream\">GetReadStream<\/a> method. This method returns a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicestreamresponse\">DataServiceStreamResponse<\/a> object that contains the binary stream of MR data, accessible from the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicestreamresponse.stream\">Stream<\/a> property.<\/p>\n<\/blockquote>\n<\/li>\n<\/ol>\n<h3>Uploading a New Image to the Data Service <\/h3>\n<p>The following steps are required to create a new <strong>PhotoInfo<\/strong> entity and binary image file in the data service.<\/p>\n<ol>\n<li>When adding a new photo, we must create a new MLE object on the client. We do this by calling <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee474331\">DataServiceCollection<\/a>.<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms132404.aspx\">Add<\/a> in the <strong>PhotoWindow<\/strong> code-behind page:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Create a new PhotoInfo object.            <br \/>PhotoInfo newPhotoEntity = new PhotoInfo(); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Ceate an new PhotoDetailsWindow instance with the current            <br \/>\/\/ context and the new photo entity.             <br \/>PhotoDetailsWindow addPhotoWindow =             <br \/>&#160;&#160;&#160; new PhotoDetailsWindow(newPhotoEntity, context); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">addPhotoWindow.Title = &quot;Select a new photo to upload&#8230;&quot;; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ We need to have the new entity tracked to be able to            <br \/>\/\/ call DataServiceContext.SetSaveStream.             <br \/>trackedPhotos.Add(newPhotoEntity); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ If we successfully created the new image, then display it.            <br \/>if (addPhotoWindow.ShowDialog() == true)             <br \/>{             <br \/>&#160;&#160;&#160; \/\/ Set the index to the new photo.             <br \/>&#160;&#160;&#160; photoComboBox.SelectedItem = newPhotoEntity;             <br \/>}             <br \/>else             <br \/>{             <br \/>&#160;&#160;&#160; \/\/ Remove the new entity since the add operation failed.             <br \/>&#160;&#160;&#160; trackedPhotos.Remove(newPhotoEntity);             <br \/>}<\/font><\/p>\n<\/blockquote>\n<p> This code instantiates and displays the <strong>PhotoDetailsWindow<\/strong> to sets properties of the new <strong>PhotoInfo<\/strong> object and the binary stream. When we are updating an existing <strong>PhotoInfo<\/strong> object, we just pass the existing <strong>PhotoInfo<\/strong> object. In this case, we pass a new <strong>PhotoInfo<\/strong> object, but we don\u2019t need to call <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.addobject\">AddObject<\/a> on the context because we are using a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee474331\">DataServiceCollection<\/a> for data binding. <\/li>\n<li>In the code-behind for the <strong>PhotoDetailsWindow<\/strong>, we use a FileStream to read an image from the local computer and pass this stream and the <strong>PhotoInfo<\/strong> object to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.setsavestream\">SetSaveStream<\/a> method:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Create a dialog to select the image file to stream to the data service.            <br \/>Microsoft.Win32.OpenFileDialog openImage = new Microsoft.Win32.OpenFileDialog();             <br \/>openImage.FileName = &quot;image&quot;;             <br \/>openImage.DefaultExt = &quot;.*&quot;;             <br \/>openImage.Filter = &quot;Images File|*.jpg;*.png;*.gif;*.bmp&quot;;             <br \/>openImage.Title = &quot;Select the image file to upload&#8230;&quot;;             <br \/>openImage.Multiselect = false;             <br \/>openImage.CheckFileExists = true; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Reset the image stream.            <br \/>imageStream = null; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">try            <br \/>{             <br \/>&#160;&#160;&#160; if (openImage.ShowDialog(this) == true)             <br \/>&#160;&#160;&#160; {             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (photoEntity.PhotoId == 0)             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Set the image name from the selected file.             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.FileName = openImage.SafeFileName; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.DateAdded = DateTime.Today; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Set the content type and the file name for the slug header.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.ContentType =             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; GetContentTypeFromFileName(photoEntity.FileName);             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; } <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.DateModified = DateTime.Today;            <\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Use a FileStream to open the existing image file.             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageStream = new FileStream(openImage.FileName, FileMode.Open); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.FileSize = (int)imageStream.Length; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Create a new image using the memory stream.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; BitmapImage imageFromStream = new BitmapImage();             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageFromStream.BeginInit();             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageFromStream.StreamSource = imageStream;             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageFromStream.CacheOption = BitmapCacheOption.OnLoad;             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageFromStream.EndInit(); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Set the height and width of the image.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.Dimensions.Height = (short?)imageFromStream.PixelHeight;             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.Dimensions.Width = (short?)imageFromStream.PixelWidth; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Reset to the beginning of the stream before we pass it to the service.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; imageStream.Position = 0; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Set the file stream as the source of binary stream            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ to send to the data service. The Slug header is the file name and             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ the content type is determined from the file extension.             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ A value of &#8216;true&#8217; means that the stream is closed by the client when             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ the upload is complete.&#160; <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; context.SetSaveStream(photoEntity, imageStream, true,             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; photoEntity.ContentType, photoEntity.FileName); <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; return true;            <br \/>&#160;&#160;&#160; }             <br \/>&#160;&#160;&#160; else             <br \/>&#160;&#160;&#160; {             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; MessageBox.Show(&quot;The selected file could not be opened.&quot;);             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return false;             <br \/>&#160;&#160;&#160; }             <br \/>}             <br \/>catch (IOException ex)             <br \/>{             <br \/>&#160;&#160;&#160; MessageBox.Show(             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; string.Format(&quot;The selected image file could not be opened. {0}&quot;,             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; ex.Message), &quot;Operation Failed&quot;);             <br \/>&#160;&#160;&#160; return false;             <br \/>}<\/font><\/p>\n<\/blockquote>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Note that we use the image stream to create a new <strong>BitmapImage<\/strong>, which is only used to automatically set the height and width properties of the image. <\/li>\n<li>When the <strong>savePhotoDetails<\/strong> button in the <strong>PhotoDetailsWindow<\/strong> is clicked, we call <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.savechanges\">SaveChanges<\/a> to send the MR as a binary stream (and any <strong>PhotoInfo<\/strong> object updates) to the data service:       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ Send the update (POST or MERGE) request to the data service and            <br \/>\/\/ capture the added or updated entity in the response.             <br \/>ChangeOperationResponse response =             <br \/>&#160;&#160;&#160; context.SaveChanges().FirstOrDefault() as ChangeOperationResponse; <\/font><\/p>\n<\/blockquote>\n<p> When <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.dataservicecontext.savechanges\">SaveChanges<\/a> is called to create a new photo, the client sends a POST request to create the MR in the data service using the supplied stream. After it processes the stream, the data service creates an empty MLE. The client then sends a subsequent MERGE request to update this new <strong>PhotoInfo<\/strong> entity with data from the client. <\/li>\n<li>When uploading a new photo (POST), we also need need to execute a query to get the new media link entry by using a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.services.client.mergeoption.aspx\">MergeOption.OverwriteChanges<\/a> to update the client object instance to to get all of the data from the newly created MLE from the data service, as follows.       \n<blockquote>\n<p><font size=\"2\" face=\"Courier New\">\/\/ When we issue a POST request, the photo ID and edit-media link are not updated            <br \/>\/\/ on the client (a bug), so we need to get the server values.             <br \/>if (photoEntity.PhotoId == 0)             <br \/>{             <br \/>&#160;&#160;&#160; if (response != null)             <br \/>&#160;&#160;&#160; {             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; entity = response.Descriptor as EntityDescriptor;             <br \/>&#160;&#160;&#160; } <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160; \/\/ Verify that the entity was created correctly.            <br \/>&#160;&#160;&#160; if (entity != null &amp;&amp; entity.EditLink != null)             <br \/>&#160;&#160;&#160; {             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Cache the current merge option (we reset to the cached             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ value in the finally block).             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; cachedMergeOption = context.MergeOption; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Set the merge option so that server changes win.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; context.MergeOption = MergeOption.OverwriteChanges; <\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Get the updated entity from the service.            <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Note: we need Count() just to execute the query.             <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; context.Execute&lt;PhotoInfo&gt;(entity.EditLink).Count();             <br \/>&#160;&#160;&#160; }             <br \/>}<\/font><\/p>\n<p><font size=\"2\" face=\"Courier New\"><\/font><\/p>\n<\/blockquote>\n<p> We have to do this because of a limitation in the WCF Data Services client POST behavior where it does not update the object on the client with the server-generated values or the edit-media link URI. <\/li>\n<\/ol>\n<p><font size=\"3\"><\/font><\/p>\n<p><font size=\"2\"><strong>Glenn Gailey <\/strong><\/font><font size=\"3\">     <br \/><\/font>Senior Programming Writer     <br \/>WCF Data Services<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this second post in the series on implementing a streaming data provider, we show how to use the WCF Data Services client library to access binary data exposed by an Open Data Protocol (OData) feed, as well as has how to upload binary data to the data service. For more information on the streaming [&hellip;]<\/p>\n","protected":false},"author":512,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[23,42,48,70,78],"class_list":["post-1153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","tag-data-services","tag-media-resource","tag-odata","tag-streaming","tag-wcf-data-services"],"acf":[],"blog_post_summary":"<p>In this second post in the series on implementing a streaming data provider, we show how to use the WCF Data Services client library to access binary data exposed by an Open Data Protocol (OData) feed, as well as has how to upload binary data to the data service. For more information on the streaming [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/1153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/512"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=1153"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/1153\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=1153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=1153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=1153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}