Enabling X-Domain access to your Data Services
05 November 09 10:43 PM | dpblogs | 0 Comments   

In the Astoria V1.5 CTP2 release, we introduced support for X-Domain and Out Of Browser access to Data Services in our Silverlight client library.

This blog post talks about how to enable Cross-Domain access to Data Services from the Silverlight client library.

I am a Service author, How do I enable X-Domain access to Data Services I host in my applications?

You would need to deploy a ClientAccessPolicy.xml file to enable X-Domain and Out Of Browser access to Data Services hosted by your applications.

The CAP.xml file should be deployed at the root of the Web Server hosting the Data Services and should not require authentication to access the file.

What is a ClientAccessPolicy.xml file?

A client access policy file defines the Services that client Silverlight applications can call
and the capabilities that these service calls can have.
Here is a sample client access policy.xml file :

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="http://ui.norhtwind.com"/>
      </allow-from>
      <grant-to>
        <resource path="/Northwind.svc" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Anatomy of  a ClientAccessPolicy.xml file:

The CAP.xml file contains a lot of sections to allow fine tuning of client access.
For a Data Service author, the following are relevant sections of the file:

1. <allow-from>

Defines all the domains that are affected by this policy.

Defines the sites that are allowed to access resources in a certain policy.

By using the allow-from element for a particular policy, you implicitly deny access for all non-listed domains.

If allow-from is empty, then the policy file grants access to no sites.

The “http-request-headers”  attribute of this node specifies the HTTP Request headers that client Service calls are allowed to pass to the Service.

For a Data Services Silverlight client application, the following headers are required

    1. X-Http-Method
    2. DataServiceVersion 
    3. Accept
    4. Content-Type
    5. Location
    6. MimeType 
    7. MaxDataServiceVersion

2. <allow-from><domain/></allow-from>

The “uri” attribute of the “domain” node specifies the domain in which the client accessing the Service has to be hosted
to be able to call the Service.

3. <grant-to>

The “<grant-to>” node specifies the Services which are allowed to be accessed by clients.

4. <grant-to><resource/></grant-to>

Each service , access to which is governed by the CAP.xml file, is represented by a <resource> node in the <grant-to> section of the CAP.xml file .

The <resource> node contains two important attributes.

    1. path : this attribute is the relative path of the Data Service
    2. include-subpaths  : this attribute specifies if paths based off of the resource path are allowed. This value should be set to true for a Data Service.

Additional references:

  1. Clientaccesspolicy.xml file Schema
  2. Making a Service Available Across Domain Boundaries
Using Data Services over SharePoint 2010 – Part 2 - CRUD
29 October 09 02:23 PM | dpblogs | 0 Comments   

In part 1 you learned how to get SharePoint 2010 and Astoria working together, how to add a Service Reference to your Client Application and how to do a basic insert.

In this installment you will see full CRUD, so you’ll learn how to do queries, data binding, updates and deletes.

The Problem:

In part 1 we created a ‘Make a Suggestion’ feature for a department Line of Business application, by storing suggestions in SharePoint 2010.

Now we need a little Silverlight application for reviewing all those suggestions and making comments on them. So we need to display interesting suggestions, to allow the user to provide a comment, or make edits and deletes.

The Solution:

Step 1: Displaying suggestions

Assuming you’ve set-up your service reference (see part 1) the next step is to create XAML to display the Suggestions:

<UserControl x:Class="DataServicesOverSharepoint.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" d:DesignWidth="640" d:DesignHeight="480">
    <Grid x:Name="LayoutRoot" ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="5"/>
            <RowDefinition Height="400"/>
            <RowDefinition Height="300"/>
            <RowDefinition Height="30" />
            <RowDefinition Height="5" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="500"/>
            <ColumnDefinition Width="5"/>
        </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding TrackedSuggestions, Mode=TwoWay}" Name="ListBox" Grid.Row="1" Grid.Column="1" ScrollViewer.VerticalScrollBarVisibility="Auto">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <StackPanel Orientation="Vertical" Margin="5">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Width="400" Text="{Binding Title}" FontWeight="Bold"/>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Width="400" Text="{Binding Description}" TextWrapping="Wrap"/>
                            </StackPanel>
                        </StackPanel>
                        <Button Content="Delete" Click="DeleteSuggestion" Tag="{Binding}" Width="50" Height="30" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel Orientation="Vertical" Margin="5" Grid.Column="1" Grid.Row="2">
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Title:" FontWeight="Bold"/>
                <TextBox Width="300" Text="{Binding ElementName=ListBox, Path=SelectedItem.Title, Mode=TwoWay}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Description:" FontWeight="Bold"/>
                <TextBox Width="300" Text="{Binding ElementName=ListBox, Path=SelectedItem.Description, Mode=TwoWay}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Created:" FontWeight="Bold"/>
                <TextBox Width="300" Text="{Binding ElementName=ListBox, Path=SelectedItem.Created, Mode=TwoWay}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Modified:" FontWeight="Bold"/>
                <TextBox Width="300" Text="{Binding ElementName=ListBox, Path=SelectedItem.Modified, Mode=TwoWay}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="100" Text="Comments:" FontWeight="Bold"/>
                <TextBox Width="300" Height="150" Text="{Binding ElementName=ListBox, Path=SelectedItem.Comments, Mode=TwoWay}" AcceptsReturn="True" />
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Grid.Row="3" Grid.Column="1" Margin="5">
            <Button Width="100" Name="btnNewSuggestion" HorizontalAlignment="Left" Content="New Suggestion"/>
            <Button Width="100" Name="btnSaveChanges" HorizontalAlignment="Right" Content="Save Changes"/>
        </StackPanel>
    </Grid>
</UserControl>

This XAML code, displays a ListBox (of suggestions) and an series of textboxes for editing the currently selected suggestion.

When running it should looks something like this:

SuggestionsVisualizer

To make this work we have a very simple class to encapsulate Data Services and the Data:

public class SuggestionContext
{
    TeamSiteDataContext _ctx;
    DataServiceCollection<SuggestionsItem> _suggestions;
    public TeamSiteDataContext DataContext
    {
        get
        {
            if (_ctx == null)
            {
                _ctx = new TeamSiteDataContext(
                    new Uri(
http://mflasko-dev/_vti_bin/listdata.svc,
                        UriKind.Absolute
                    )
                 );
            }
            return _ctx;
        }
    }
    public DataServiceCollection<SuggestionsItem> TrackedSuggestions
    {
        get
        {
            if (_suggestions == null)
                _suggestions = new DataServiceCollection<SuggestionsItem>(
                    DataContext);
            return _suggestions;
        }
    }
}

This class has two properties, both evaluated on first access.

One gets the DataServiceContext and the other gets a DataServiceCollection which will hold, and track changes to, a collection of Suggestions.

The SuggestionContext is then exposed as a property of our Silverlight UserControl:

private SuggestionContext _currentContext;
public SuggestionContext CurrentContext {
    get {
        if (_currentContext == null)
            _currentContext = new SuggestionContext();
         return _currentContext;
    }
}

Next in the constructor of our UserControl we use this as the DataContext for our layout root, we call GetSuggestionsWithNoComments() to retrieve the interesting suggestions, and finally we hookup some event handlers for our buttons, so we can add a new suggestion and save any changes we make back to the database.

public MainPage()
{
    InitializeComponent();
    GetSuggestionsWithNoComments();
    LayoutRoot.DataContext = CurrentContext;
    this.btnSaveChanges.Click += new RoutedEventHandler(SaveChanges_Click);
    this.btnNewSuggestion.Click += new RoutedEventHandler(AddNewSuggestion);
}

The GetSuggestionsWithNoComments() method looks like this:

public void GetSuggestionsWithNoComments()
{
    var query = (
           from suggestion in CurrentContext.DataContext.Suggestions
           where suggestion.Comments == null
           select suggestion
    ) as DataServiceQuery<SuggestionsItem>;

    query.BeginExecute(
        (IAsyncResult asyncResult) => Dispatcher.BeginInvoke(() =>
        {
            DataServiceQuery<SuggestionsItem> queryResults = asyncResult.AsyncState as DataServiceQuery<SuggestionsItem>;
            if (queryResults != null)
            {
                CurrentContext.TrackedSuggestions.Clear(true);
                CurrentContext.TrackedSuggestions.Load(
                     queryResults.EndExecute(asyncResult)
                );
            }
        })
        , query
     );
}

It executes an asynchronous query to retrieve the interesting suggestions and load them into the CurrentContext.TrackedSuggestions collection. Which in turn causes the ListBox to fill, because of the data binding we’ve set up.

Step 2: Inserting, Editing and Deleting suggestions

Now in our XAML we’ve already setup two way data binding from our textboxes back to the suggestion selected in the ListBox, so as we make changes in the TextBoxes the Suggestion is modified, and those changes are tracked by the DataServiceCollection.

So that covers Editing.

Insert is handled by the ‘New Suggestion’ button. The event handler looks like this:

void AddNewSuggestion(object sender, RoutedEventArgs e)
{
    CurrentContext.TrackedSuggestions.Add(
        new SuggestionsItem {
            Title = "{Enter a title}",
            Description = "",
            Modified = DateTime.Now,
            Created = DateTime.Now
        }
    );
    ListBox.SelectedIndex = CurrentContext.TrackedSuggestions.Count - 1;
}

As you can see this creates a new Suggestion, adds it to the DataServiceCollection, and then tells the ListBox to select the new Suggestion so it can be modified via our TextBoxes.

In our XAML we added a Delete button to each ListBoxItem, this event is bound to those buttons:

private void DeleteSuggestion(object sender, RoutedEventArgs e)
{
    Button b = sender as Button;
    SuggestionsItem toDelete = b.Tag as SuggestionsItem;
    CurrentContext.TrackedSuggestions.Remove(toDelete);
}

This relies on the fact that when during DataBinding we put the Suggestion in the button’s Tag property, so all we do when the button is clicked, is retrieve the current Suggestion and remove the suggestion from the TrackedSuggestions collection. This is interpreted as a delete.

Step 3: Submitting your changes

Because we are using a DataServiceCollection, every Insert, Edit and Delete is automatically tracked for us.

But as yet they haven’t been committed to the server.

To do that you have to click the “Save Changes” button, which calls this code:

void SaveChanges_Click(object sender, RoutedEventArgs e)
{
    CurrentContext.DataContext.BeginSaveChanges(
        (IAsyncResult asyncResult) =>
            Dispatcher.BeginInvoke(
                () =>
                {
                    CurrentContext.DataContext.EndSaveChanges(asyncResult);
                    GetSuggestionsWithNoComments();
                }
            )
        , CurrentContext
    );
}

As per usual the request is invoked asynchronously, in this case by calling BeginSaveChanges.

One thing to note is that once we’ve actually saved the changes we refresh the list of Suggestions by calling GetSuggestionsWithNoComments() again.

The idea here is that once we’ve edited some suggestions they may not longer be interesting for us, or there maybe some new suggestions on the server.

Summary:

As you can see it is really easy to create a Silverlight application that uses Data Services to query and manipulate list data.

In part 3 we look into X-Domain Policy which is important if your Silverlight application isn’t hosted on the same web-server as Sharepoint.

As always don’t hesitate to leave a comment.

Alex James
Program Manager Microsoft

Using Data Services over SharePoint 2010 – Part 1 – Getting Started
21 October 09 11:21 AM | dpblogs | 5 Comments   

ADO.NET Data Services 1.5 and SharePoint 2010 allow developers to write applications against SharePoint Lists using the familiar Data Services Client programming model.

Setup

The SharePoint 2010 beta will become generally available in November.

In order to use Data Services with SharePoint 2010 Beta, ADO.NET Data Services 1.5 must be installed on your server *before* you install SharePoint 2010

And then to program against a Data Services enabled SharePoint box you need either:

  • VS 2008 SP1 with the ADO.NET Data Services 1.5 installed (CTP 2 or higher)

    or
  • VS 2010 (Beta 2 or higher)

Where is your Data Service Endpoint?

Assuming you’ve got everything setup and working the first thing you need to know is where your Data Service endpoint is installed.

If your SharePoint site is http://mflasko-dev/ (thanks Mike) then your Data Services endpoint will be http://mflasko-dev/_vti_bin/listdata.svc.

If you open one of these endpoints up in Internet Explorer you’ll see something like this:

DataServiceRoot

As you can see this is a standard Data Services Atom feed, listing all the Lists on the SharePoint site.

Cool.

Once you know where your Data Service is located, the next step is to write your Data Services Client application.

Create the Sharepoint Application:

But first to demonstrate how easy this is, I’ve used SharePoint to create the simplest of all Suggestion Tracking applications.

You can follow along by following these simple steps:

  1. Create a ‘Suggestions’ list which is based on an ‘Issues’ list.
  2. Finished!

The resulting list looks something like this:

Suggestions 

The idea is that this list will capture all the suggestions users have for making a departmental line of business (LOB) application better.

But rather than making people go to the SharePoint site to make the suggestion, we want to allow the users to do it right in the LOB application.

Talking to Sharepoint using Data Services:

The first step as always to add a service reference, using the location of the Data Service that exposes SharePoint data (i.e. http://mflasko-dev/_vti_bin/listdata.svc)

AddServiceReference

Once you’ve done this you will have CLR classes representing the types in each list, and you will have a strongly typed DataServiceContext called TeamSiteDataContext that allows you to access the data:

ObjectBrowser

Rather than focusing on how the user enters the suggest in your LOB application, lets focus on how to POST that suggestion to Sharepoint.

To do that you need to write a method something like this:

public void PostSuggestion(string title, string description)
{
   TeamSiteDataContext ctx = new TeamSiteDataContext(
        new Uri(
           
http://mflasko-dev/_vti_bin/listdata.svc
            UriKind.Absolute
        )
   );
   ctx.AddToSuggestions(
      new SuggestionsItem{
          Title = title, 
          Description = description
      }
   );
   ctx.SaveChanges();
}

As you can see this is very easy.

In an environment like Silverlight it is a little more complicated because whenever you cross a network boundary have to deal with the Async and Threading issues. Which means you can’t use SaveChanges() directly.

You have to use the standard BeginXXX() and EndXXX() async pattern and you need to use the Dispatcher to ensure the results are marshaled back on the UI thread:

ctx.BeginSaveChanges(
      (IAsyncResult result) => Dispatcher.BeginInvoke(
          () => ctx.EndSaveChanges(result)),
       ctx
   );

In future blog posts we will dig into this in more detail, covering topic like Query / Update / Data Binding, Blob Handling and security policies over Sharepoint.

As always we are keen to hear your comments.

Alex James
Program Manager
Microsoft

Share your data across data sources (Sharepoint, SQL Server, Azure, Reporting Services, etc) & applications (.NET, Silverlight, Excel, etc) using Data Services
19 October 09 08:32 PM | dpblogs | 2 Comments   

This week at the SharePoint conference, Pablo Castro will be announcing that the next version of SharePoint natively integrates with data services such that all SharePoint lists will be exposed as an ADO.NET Data Service.  This means you can now program against SharePoint list data using all the VS tools and runtime client libraries (.NET, Silverlight, AJAX, Java, PHP, etc…) which support ADO.NET Data Services.  Also, since the Data Service interface is just plain HTTP and XML/Atom or JSON, pretty much any environment with an HTTP stack can now browse, update and interact with list and document data in SharePoint. We are very excited to be able to talk about SharePoint’s data service integration (more code-centric blogs to come on this topic) as this has been an ask we hear a lot each time we present data services.

This integration is also a good example of a step towards our larger vision for data services and, more generally, open data access on the web.  The remainder of this post outlines our roadmap around data services and what parts of that roadmap we are announcing this week.

First, a bit of context…

Successful applications collect lots of valuable data. Often it is relatively easy to get data into applications but hard to get it out or to have multiple applications to use one another’s data. Part of the problem is lack of a simple, uniform way of exchanging data across systems. Server side applications such as SharePoint server are examples where it would be extremely valuable to have a general purpose data service interface. Another example is SQL Server Reporting Services, as reports frequently become the official entry point for application data. Excel and the analysis services clients in SQL Server are examples of client side applications that would greatly benefit from having readily access to data managed by applications of all kinds, from SharePoint sites to Reporting Services reports in existing applications to custom applications that expose data as services. Client mash-ups also consolidate data from multiple sources to provide valuable cross-application perspective, provided that they can actually access data from all systems.

Background on the approach

Services, instead of APIs, is what is becoming common ground for interaction across tiers or across applications, both on the web and inside organizations. Microsoft has been working on data-centric service interfaces that enable simple, effective data sharing within and across applications. The first materialization of this effort is the ADO.NET Data Services framework that shipped last year as part of .NET 3.5 SP1. The approach taken is to use a RESTful data service interface built on top of standard, broadly available concepts and technologies such as HTTP and AtomPub. Conventions are defined on top such that things such as metadata discovery is possible

What we are announcing

A number of products and developer tools are all now aligned around this single RESTful data service interface. More specifically:

Developer tools:

We updated the protocol itself as well as our frameworks and developer tools in Visual Studio 2010, .NET 4.0 (starting with Beta 2) and Silverlight 4.  We’ll also release an update to .NET 3.5 SP1.

SharePoint:

Starting with SharePoint 2010 (beta release to come in November) all SharePoint sites are automatically exposed as RESTful data services that follow the ADO.NET Data Services convention. Now any client with an HTTP stack can read and write to SharePoint by just using simple HTTP methods and Atom (XML) or JSON formatted data. All the rich clients that work with Data Services will work with SharePoint out of the box.

Reporting Services:

Starting with SQL Server 2008 R2, all reports created with SQL Server Reporting Services will expose an option to render as an Atom feed that follows the Data Services convention as well. This makes it possible for developers and information workers to see the data “underneath” a report (whether it displays as tables, charts, etc.) and use it in their own applications.

Excel and Microsoft SQL Server PowerPivot for Excel 2010 (aka “Project Gemini”):

Also starting with SQL Server 2008 R2, the PowerPivot plug-in for Excel allows information workers to bring data from all sources for analysis will natively understand and load data from any Data Service. Now information workers can obtain data from reports, SharePoint sites, public sites that expose reference data and even custom applications and load it directly into the data analysis environments.

Cross-platform clients:

in addition to the .NET, Silverlight and AJAX clients that were already available, Microsoft sponsored open-source projects to create a PHP and a Java client for Data Services. Both are already publicly available.

All these products introduce first class support for producing or consuming the Data Services protocol, enabling data sharing scenarios for both developers and information workers. They join other already-existing services using the Data Services protocol such as the Windows Azure Table Store.

Stay tuned, more to come at the PDC & TechEd conferences later this year.

Mike Flasko

ADO.NET Data Services, Lead Program Manager

ADO.NET Data Services – Version Headers
07 October 09 11:37 PM | dpblogs | 0 Comments   

Peter Qian, a developer on the data services team, has posted a two part series on the versioning headers used by ADO.NET Data Services to ensure a client or server never misinterprets a payload or URI.  You can check out his posts here:

Part 1 - Versioning Protocol of Astoria

Part 2 - Versioning Protocol of Astoria II

 

-Mike Flasko

ADO.NET Data Services, Program Manager 

‘Restlet’ Java Framework Now with ADO.NET Data Services Support
29 September 09 08:27 AM | dpblogs | 0 Comments   

Yesterday on the interoperability blog it was announced that Noelios Technologies is shipping a new version of the Restlet open source project (a lightweight REST framework for Java) that includes an extension for ADO.NET Data Services. 

This is the second interoperability project over the last month or so which leverages data services. Prior to this, the interoperability team announced the release of a PHP toolkit for data services.

For a complete list of interoperability bridges available (which target data services and other technologies), check out this URL: http://www.interoperabilitybridges.com/

--Mike Flasko

ADO.NET Data Services, Program Manager

Introduction to Data Binding in Silverlight 3 with CTP2
17 September 09 06:18 PM | dpblogs | 4 Comments   

This blog post is an introduction to the data binding capabilities for Silverlight 3 we first added for Silverlight 2 in Data Services v1.5 CTP1 and have updated to Silverlight 3 in CTP2. We also took the feedback we received in CTP1 and made some updates to the feature. Since this is a CTP release of this is a CTP release of this feature we eagerly look forward to hearing your feedback.

Introduction to Data Binding

In a previous post I introduced a new feature we included in ADO.NET Data Services v1.5 CTP2 that enables data binding. I outlined the feature and then showed how it can be used in WPF to create a client application that uses two-way data binding with WPF controls. The following blog post is a variance on the first blog post that shows how a similar application can be created using Silverlight 3. For more information on the new binding feature, you should go read the introduction to that post; found here.

Walkthrough

The following is a walkthrough of using data binding in a Silverlight 3 application.

To get started, you'll want to download all of the required software I use in the walkthrough: 

  • Visual Studio 2008 SP1 (here)
  • ADO.NET Data Services v1.5 CTP2 (here)
  • Silverlight 3 SDK (here)
  • Silverlight tools for Visual Studio SP1 (here)

Step 1 and 2: Create an ADO.NET Data Service v1.5

The service you will use for this walkthrough is identical to the service I created in my introduction to databinding and WPF. For this step, go to this blog post and follow step 1 and 2 of the walkthrough and then come back here and continue with step 3.

Step 3: Create client proxy code with binding enabled.

After setting the environment variable in step 2, open the solution you created in step 1 and create a new Silverlight project.

image

Once you have created a SL client project, the next step is to generate client side types. To do this, find the DatabindingSLClient project in the solution explorer, right-click the project and select Add Service Reference... In the Add Service Reference dialog, click the Discover button. The northwind.svc service will show up in the Service window. Enter NorthwindService as the Namespace value and select OK. This wizard will generate a set of client side types that can be used to interact with the service created in step 1.

image

If this step is done correctly, you will see a new NorthwindService node under the Service References Node in the solution explorer. As well, you will see a reference to Microsoft.Data.Services.Client in the references node; if you do not see the reference to Microsoft.Data.Services.Client or you see a reference to System.Data.Services.Client go to the ADO.NET Data Services blog and read this post about enabling ADO.NET Data Services v1.5 features in Visual Studio and then repeat the Add Service Reference Step.

clip_image006

When the above references are correctly showing the Silverlight project, right click the Microsoft.Data.Services.Client reference and select Properties. In the properties window, change the Copy Local property to True.

clip_image008

The next part of this step is to create a new instance of the ADO.NET Data Services client context and connect to the service created in step 1. To do this, add the following code to the Page.xaml.cs file to create a connection to the service.

NorthwindEntities nwsvc = new NorthwindEntities(new Uri("/Northwind.svc", UriKind.Relative));
public MainPage()
{
    InitializeComponent();
}

Now, create an interface that you can bind the result of a query to. The service you created in step 1 exposes a set of Suppliers and a set of Products from the Northwind database with a one-to-many relationship between them. The XAML code below will create a datagrid to display the suppliers. It will also create a RowDetailsTemplate inside each row of the datagrid to display the supplier’s products. This type of binding is called master-detail binding.

The code below uses standard Silverlight binding semantics. The columns of the supplier datagrid are each bound to a property of the supplier object through the Binding="{Binding ProductID}"tag.

Paste the following code snippet into the mainPage.xaml file:

<Grid x:Name="supplierGrid" Background="White" Width="750" Height="400">
    <data:DataGrid x:Name="dgSuppliers" Height="300" Width="749" AutoGenerateColumns="False"
               VerticalAlignment="Top" RowDetailsVisibilityMode="VisibleWhenSelected" RowDetailsVisibilityChanged="dgSuppliers_RowDetailsVisibilityChanged">
        <data:DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <data:DataGrid x:Name="dgSupplierProduct" Width="700" AutoGenerateColumns="False"
                             HeadersVisibility="Column" HorizontalAlignment="Right"
                             SelectionChanged="dgSupplierProduct_SelectionChanged"
                               ItemsSource="{Binding Products}">
                    <data:DataGrid.Columns>
                        <data:DataGridTextColumn Header="ID" Binding="{Binding ProductID}"/>
                        <data:DataGridTextColumn Header="Name" Binding="{Binding ProductName}"/>
                        <data:DataGridTextColumn Header="QuantityPerUnit" Binding="{Binding QuantityPerUnit}"/>
                        <data:DataGridTextColumn Header="Price" Binding="{Binding UnitPrice}"/>
                        <data:DataGridTextColumn Header="InStock" Binding="{Binding UnitsInStock}"/>
                    </data:DataGrid.Columns>
                </data:DataGrid>
            </DataTemplate>
        </data:DataGrid.RowDetailsTemplate>
        <data:DataGrid.Columns>
            <data:DataGridTextColumn Header="ID" Binding="{Binding Path=SupplierID}"/>
            <data:DataGridTextColumn Header="Name" Binding="{Binding Path=CompanyName}"/>
            <data:DataGridTextColumn Header="Address" Binding="{Binding Path=Address}"/>
            <data:DataGridTextColumn Header="City" Binding="{Binding Path=City}"/>
            <data:DataGridTextColumn Header="Region" Binding="{Binding Path=Region}"/>
        </data:DataGrid.Columns>
    </data:DataGrid>
</
Grid>

Edit the following attributes of your window: Width="750" Height="400" to properly display the controls.

The next step to enable binding to these Silverlight controls is to set the ItemsSource of the datagrid in the page you just created to the result of a query for suppliers from the service created in step 1. This is done by executing an asynchronous ADO.NET Data Services query on the context for the set of suppliers and loading the query result into a DataServiceCollection. The entities in this collection will implement INotifyPropertyChanged and INotifyCollectionChanged. To do this, add the following code to the constructor for the page:

public MainPage()
{
    InitializeComponent();
    var q = nwsvc.Suppliers;

    //create an asynchronous query to get the set of suppliers
    q.BeginExecute(
            delegate (IAsyncResult asyncResult)
            {
                Dispatcher.BeginInvoke(
                    () =>
                        {
                            DataServiceQuery<Supplier> query = asyncResult.AsyncState as DataServiceQuery<Supplier>;
                            if (query != null)
                            {
                                //create a tracked DataServiceCollection from the result of the asynchronous query.
                                suppliers = DataServiceCollection.CreateTracked<Supplier>(nwsvc, query.EndExecute(asyncResult));
                                //set the items source of the grid to the DataServiceCollection of suppliers. This collection
                                //will be tracked and all changes made will be reflected on the DataServiceContext
                                this.dgSuppliers.ItemsSource = suppliers;
                            }
                        }
                    );
            },
            q  
        );
}

The final step is to implement the RowDetailsVisibilityChanged event handler that executes when a new row is selected in the grid. This method will dynamically load in the products to display in-line for the currently selected supplier using a call to loadProperty. Insert the following code into the event handler:

private void dgSuppliers_RowDetailsVisibilityChanged(object sender, DataGridRowDetailsEventArgs e)
{
    if (e.Row.DataContext is Supplier)
    {
        //get the currently selected item in the grid
        Supplier supplier = e.Row.DataContext as Supplier;

        //ensure the entity is not new or we won't be able to query for it's products
        if (nwsvc.GetEntityDescriptor(supplier).State != EntityStates.Added)
        {
            //create an async call to load the products property of the current supplier
            Dispatcher.BeginInvoke(
                () =>
                {
                    nwsvc.BeginLoadProperty(supplier, "Products",
                        delegate(IAsyncResult asyncResult)
                        {
                            //this delegate will execute when the results of the async query have returned
                            nwsvc.EndLoadProperty(asyncResult);

                        }, supplier);
                }
            );
        }
    }
}

Once this is complete, compile the project and run it. This datagrid in this example takes advantage of the RowDetailsTemplate in Silverlight to display the products directly inline when a supplier is selected. The result will be:

image 

Step 4: Two-way Binding

Up to this point in the walkthrough, you have created a Silverlight client and bound the result of a query to the service to a pair of listview controls in the client. This type of binding you have done so far has all been one-way binding. The DataServiceCollection you used at the end of step 3 also supports two-way binding. This means that any changes made to the collection or items in the collection will propagate to the service after a call to BeginSaveChanges() has completed executing.

This final step will walk you through adding buttons that will add items to the collection of products and take advantage of two-way binding to have those changes propagate to the service and the backing northwind database.

To start, add the following XAML code to the window1.xaml file to create two buttons to that will add a product from the list of products and save the changes to the service.

<Button x:Name="saveBtn" Width="90" Height="25" Margin="600, 315, 50, 50" Click="saveBtn_Click" Content="Save"></Button>
<
Button x:Name="addProductBtn" Width="90" Height="25" Margin="400, 315, 50, 50" Click="addProductBtn_Click" Content="Add Product"></Button>
<
Button x:Name="addSupplierBtn" Width="90" Height="25" Margin="200, 315, 50, 50" Click="addSupplierBtn_Click" Content="Add Supplier"></Button>

After adding this code the client application will be:

image

The final part of this step is to handle the add and save button click events.

Add the following code to the add supplier buttons click event. This method will create a new supplier object and add it to the collection of suppliers.

private void addSupplierBtn_Click(object sender, RoutedEventArgs e)
{
    //create a new supplier and add it to the supplier collection
    suppliers.Add(new Supplier());
}

Add the following code to the addProductBtn_Click event to create a new product when the add button is selected. The following code creates a new Product object and adds it to the list of products for the currently selected supplier.

private void addProductBtn_Click(object sender, RoutedEventArgs e)
{
    //get the currently selected supplier entity
    Supplier supplier = this.dgSuppliers.SelectedItem as Supplier;

    //add a new product to the supplier
    //because the collection of products is a tracked collection this operation
    //will be translated into an insert operation on the DataServiceContext
    if (supplier != null)
        supplier.Products.Add(new Product());
}

Add the following code to handle the save button click. This button calls BeginSaveChanges on the context which will cause any operations that have been performed on the context to be sent to the service. As with all network calls in Silverlight the SaveChanges call need to be asynchronous.

private void saveBtn_Click(object sender, RoutedEventArgs e)
{
    //create an asynchronous save call
    nwsvc.BeginSaveChanges(SaveChangesOptions.Batch,
        delegate(IAsyncResult asyncResult)
        {
            Dispatcher.BeginInvoke(
                () =>
                {
                    nwsvc.EndSaveChanges(asyncResult);
                }
                );
        }, nwsvc
        );
}

Your project is now complete. When you make a change you then click the save button to persist the changes to the service.

 

Providing Feedback

We have created a new forum dedicated to providing feedback on "pre-release" versions of data services such as this CTP.  Please direct all your questions and comments about this feature this new forum which is available at: (http://social.msdn.microsoft.com/Forums/en-US/dataservices/threads). 

Note: The forum intended for questions on currently shipping versions of ADO.NET Data Services is still available at: (http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/threads/ )

We look forward to hearing your feedback.

Shayne Burgess

ADO.NET Data Services, Program Manager

More on Using Data Services & Silverlight 3 in xDomain & Out-Of-Browser Scenarios
10 September 09 08:18 AM | dpblogs | 0 Comments   

Phani recently posted part 2 of his two part series on using the ADO.NET Data Services v1.5 CTP2 Silverlight client library in xdomain and out-of-browser scenarios.  You can find both posts here:

Part 1: Using the ADO.NET Data Services Silverlight client in x-domain and out of browser scenarios – I

Part 2: Using the ADO.NET Data Services Silverlight client library in x-domain and out of browser scenarios – II (Forms Authentication)

 

-Mike Flasko

ADO.NET Data Services, Program Manager

Jumpstart your PHP + ADO.NET Data Services Development
08 September 09 09:21 PM | dpblogs | 0 Comments   

To get up and running quickly with the PHP toolkit for data services check out this walkthrough post by Phani from the data services team: http://blogs.msdn.com/phaniraj/archive/2009/09/08/using-the-php-toolkit-with-ado-net-data-services.aspx 

 

-Mike Flasko

ADO.NET Data Services, Program Manager

Using the ADO.NET Data Services Silverlight client in x-domain and out of browser scenarios – I
03 September 09 06:09 PM | dpblogs | 5 Comments   

With the release of ADO.NET Data Services v1.5 CTP2, you can now use the Silverlight Astoria client library to access Cross-Domain services
and applications written with the new client library can go out of browser.

The new Client Http networking stack introduced in SL3 supports the standard and custom HTTP Verbs(GET/PUT/POST/DELETE/MERGE)
as well as access to the response status codes required for a full fidelity REST-based client experience in Silverlight.
Working with the SL networking team, we modified the Astoria client library to use the networking stack
in cross-domain and out-of-browser scenarios.
With this change, we are now able to support Cross-Domain calls allowed by ClientAccessPolicy.xml files
and applications written with the Silverlight Astoria client library can go Out Of Browser.

I have an existing SL app based on the Astoria client library , what do I need to do to enable my application to
access X-Domain Data Services and go Out Of Browser ?

1. Recompile your application with a reference to the new Silverlight client library .
2. Update the URI of the Data Service to point to the absolute URI of the Data Service in its new location.
3. Drop a ClientAccessPolicy.xml file into the root of the Webserver Hosting your Data Service.
4. Deploy the newly created application to the Webserver.
5. In your Silverlight application code, find all the places that you call EndExecute/EndSaveChanges/EndExecuteBatch
and check if the call is being marshaled back to the UI thread , else Silverlight will throw an invalid Cross-Thread Access Exception.
To fix this, always dispatch the call to EndExecute to the UI thread using Dispatcher.BeginInvoke.
As an example:

nwContext.BeginExecute<Customers>(new Uri("Customers"),
(asResult) =>
{
 Dispatcher.BeginInvoke(
   () =>{
   CustomersGrid.ItemsSource = nwContext.EndExecute<Customers>(asResult).ToList();
   }
   );                     
}, someUserState);

Now , let’s walk through a demo application that illustrates how to build a Silverlight application
that accesses an ADO.NET Data Service from a different domain than the Silverlight application and can also run Out-Of-Browser.

We have a sample Silverlight application that looks like this :

Now , let’s walk through a demo application that illustrates how to build a Silverlight application
that accesses an ADO.NET Data Service from a different domain than the Silverlight application and can also run Out-Of-Browser.

We have a sample Silverlight application that looks like this :

clip_image002

1. SilverlightApplicationHost is the Web application hosting your Silverlight XAP , think of this as UI.Foo.Com.
2. DataServiceHost is the web application hosting the ADO.NET Data Service , think of this as API.Foo.Com
3. DataServicesXDomainSLClient is the Silverlight application that runs in UI.Foo.Com and consumes the Data Service from API.Foo.Com.

Since the DataServiceHost site hosts the Data Service, it also hosts the ClientAccessPolicy.xml file which allows apps from the
domain hosting the Silverlight app to access resources hosted at API.Foo.com

clip_image002[8]

The Silverlight application, DataServicesXDomainSLClient, has a Service Reference to the Data Service hosted at DataServiceHost.
It has two buttons which download an Entity Set called “Publications” from the Data Service and looks like this.

clip_image001

The “Load Publications Via Uri” downloads Entities from the “Publications” entity set and the Click handler looks like this :

void btnLoadPublications_Click(object sender, RoutedEventArgs e)
{
object userState = null;
//download the Publications and sort the Publications in descending order of Name
publicationContext.BeginExecute<Publication>(
  new Uri("/Publications?$expand=PublishedFrom&$orderby= Name desc", UriKind.Relative),
(asResult) =>
  {
  //Dispatch the EndExecute call to the UI thread
  Dispatcher.BeginInvoke(
   () =>
   {
     var IEnumerableOfPublications = publicationContext.EndExecute<Publication>(asResult);
     PublicationsGrid.ItemsSource = IEnumerableOfPublications.ToList();
   }
   );
   }, userState);
}

The “Load Publications Via Linq” downloads entities via a Linq Query and the Click Handler looks like this :

void btnLoadPublicationsLinq_Click(object sender, RoutedEventArgs e)
{
 object userState = null;
 //download the Publications and sort the Publications in ascending order of Name
 var publicationLinqQuery = (from pub in 
publicationContext.CreateQuery<Publication>("Publications")
.Expand("PublishedFrom") orderby pub.Name ascending select pub) as DataServiceQuery<Publication>; publicationLinqQuery.BeginExecute( (asResult) => { //Dispatch the EndExecute call to the UI thread Dispatcher.BeginInvoke( () => { var IEnumerableOfPublications = publicationLinqQuery.EndExecute(asResult); PublicationsGrid.ItemsSource = IEnumerableOfPublications.ToList(); }); }, userState); }

Clicking the “Install Me” button installs the app and launches it Out Of Browser.
Here is what the “Install Me” button click handler looks like :

/// <summary>
/// Installs the Silverlight application as an Out Of Browser application
/// </summary>
void InstallApplication(object sender, RoutedEventArgs e)
{
  //Install the app
  App.Current.Install();
  //Hide the "Install Me" button
  btnInstallOOBApp.Visibility = Visibility.Collapsed;
 }

The buttons which do a Linq Query and a URI query still work , without any changes to the code .
clip_image001[8]

Debugging Out Of Browser Silverlight Applications

To debug your Out Of Browser Silverlight apps , follow these steps.

1.  Open the properties of the Silverlight application.

clip_image002[10]

2. Select the Out Of Browser application which has the name of the project with the Page hosting the SL application.
Which , in this case , is SilverlightApplicationHost.

clip_image002[12]

3. Hit F5 and select yes when this prompt comes up.
This prompt is warning you that you have a Service Reference to a Data Service.
In In-Browser Silverlight apps , running the SL app directly will launch it off of the file system ( i.e c:\Projects\yourProjectPath),
and you wont be able to make calls to data services  as this would constitute a Cross-Scheme request and isn’t allowed.

While debugging your Out Of Browser Silverlight application, you can ignore this prompt.

clip_image004

Is the SL3 Client HTTP stack used by the ADO.NET Data Services v1.5 CTP2 client library for all requests?

No, the SL3 Client Http Stack is only used for Out-Of-Browser and Cross-domain network access.
The XmlHttp based stack is still used for In Browser, Same Domain network access to preserve backward compatibility.
You can customize this by setting a new property on the client library called HttpStack.
HttpStack which has 3 possible values:

1. Auto: Client library decides when to switch networking stacks.
2. XmlHttp: The classic networking stack based on XmlHttpRequest
3. ClientHttp: The new SL3 Client HTTP  stack

The Default value is Auto, and you should leave it as it is, unless you need to customize the networking stack we use.
When the HttpStack is set to Auto, the client library automatically switches the networking stack it uses to talk to
the Data Service.

Should I set the HttpStack on the DataServiceContext instance so that I get X-Domain and OOB data access?
Nope, you can just leave the HttpStack property at Auto and we will figure out which stack to use and when.
We use XmlHttp only in a scenario where the Silverlight XAP and the Data Service are hosted in the same domain.
For other scenarios we use the ClientHttpStack. The below table is helpful in understanding when we automatically switch stacks.

 

Silverlight App

Data Service

Out Of Browser

Networking stack

http://foo.com

http://foo.com

False

XmlHttp                    

http://foo.com

http://foo.com

True

ClientHttp

http://UI.foo.com

http://API.foo.com

False/True

ClientHttp

Features VS Networking Stack

Feature

XmlHttp

ClientHttp

Cross Domain Data Access

No

Yes

Out Of Browser Data Access

No

Yes

NTLM Based Authentication

Yes

No*

Same Domain Data Access

Yes

Yes

Cookie Based Authentication

Yes

Yes

Cookie store shared with browser

Yes

No*

*We are working over the next few releases of Silverlight to extend the ClientHttp stack such that it supports
all possible scenarios.

Authentication Schemes supported

With the new networking stack, in X-Domain and OOB scenarios, the client library is now restricted to the same options as any other application that uses the SL3 networking stack.
The main concern is that NTLM based authentication schemes such as Windows Authentication or BASIC Authentication are not supported in X-Domain and Out Of Browser scenarios.
The only authentication schemes that are supported are cookie-based authentication schemes such as ASP.NET Forms Authentication.
An example of using the new client library with ASP.NET Forms Authentication will be shown in Part II of this blog post.

You can download the sample application shown here at the bottom of the post.

Phani Raj
Engineer, ADO.NET Data Services .

Introduction to Data Binding in CTP2
01 September 09 03:08 PM | dpblogs | 2 Comments   

This blog post is an update to an introduction to the data binding capabilities we first added in Data Services v1.5 CTP1. In CTP2 we have taken the feedback we received from CTP1 and made some updates to the data binding feature. Since this is a CTP release of this feature we eagerly look forward to hearing more of your feedback.

Introduction to Data Binding

A new collection type, DataServiceCollection, has been added to the client library which extends ObservableCollection and supports two way binding for client code. It is now possible to auto generate client side types that implement the INotifyPropertyChanged and INotifyCollectionChanged interfaces using the add service reference gesture.

This means that, when data binding has been enabled, any changes made to contents of a DataServiceCollection or the entities in the collection will be reflected on the client context; any subsequent calls to SaveChanges() on that context will then persist those changes on the service. As well, any changes made to the entities in the context, through a subsequent query to the data service, will automatically be reflected on the items in the DataServiceCollection.

This also means that the DataServiceCollection, because it implements the standard binding interfaces, can be bound as the DataSource to most WPF and Silverlight controls.

Here are some examples of different ways to create a DataServiceCollection using the ADO.NET Data Services client library. In all of these examples, the queries are being executed against a service named “nwsvc” that exposes two types: products and suppliers that have a one-to-many relationship.

Example 1: Creating a DataServiceCollection of all products.

DataServiceCollection<Products> products =
     DataServiceCollection.CreateTracked<Products>(
                            nwsvc,
                            from p in nwsvc.Products
                            select p
                            );

Example 2: Creating a DataServiceCollection of all products and their associated suppliers.

DataServiceCollection<Products> products =
     DataServiceCollection.CreateTracked<Products>(
                    nwsvc,
                    from p in nwsvc.Products.Expand("Suppliers")
                    select p
                    );


Example 3: Creating a new DataServiceCollection of products. This creates a new empty collection of products without issuing a query against the service. New product objects can be created and added to this collection.

DataServiceCollection<Products> products =
     DataServiceCollection.CreateTracked<Products>(
                    nwsvc);

Walkthrough

The following is a walkthrough of using data binding in a WPF application. The walkthrough is a basic introduction to binding in ADO.NET Data Services, if you are already familiar with binding in WPF and Data Services you may want to wait for the next blog post on data binding that will cover more advanced concepts.

To get started, you'll want to download all of the required software I use in the walkthrough: 

  • Visual Studio 2008 SP1 (here)
  • ADO.NET Data Services v1.5 CTP2 (here)

Step 1: Create an ADO.NET Data Service v1.5 Service

Create a new Web Application (named DatabindingDemo):

image

Our first data access related task is to generate the Entity Framework-based data access layer to the Northwind database.  Right click the ASP.NET project and select 'Add New Item', then select 'ADO.NET Entity Data Model'.  Name the new item nw.edmx:

image

After clicking ‘Add’ on the screen above, a wizard will open to walk you through creating the Entity Data Model for the Northwind database. Use the default settings until you get to the point where you choose the database objects to include in the model. For this demo, choose only the Products and Suppliers tables.

image

Once you reach the ‘Choose Your Database Objects’ screen, select the two tables and click ‘Finish’. This will open the Entity Data Model designer view.  This view allows you to customize the auto-generated conceptual data model. To learn more about the mapping capabilities of the Entity Framework, see the MSDN page here.

clip_image018

Create a v1.5 CTP2-based ADO.NET Data Service over this model. To create the data service, right click the ASP.NET project and select 'Add New Item'.  Add an 'ADO.NET Data Service v1.5 CTP2' item called nw.svc

image

This will generate a file (nw.svc.cs) which represents the skeleton of a v1.5 data service. All we need to do now is point the data service at the data model to be exposed as a REST-service and we’ll be set. The snippet below shows the 2 or so lines of code you need to write to do this. One thing to note is that a data service is locked down by default, so we need to take explicit steps to open access to it. For this simple application we’ll enable read and write access to the entire model quickly using the call to ‘SetEntitySetAccessRule’ shown below.

public static void InitializeService(DataServiceConfiguration config)
{
    // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
    // Examples:
     config.SetEntitySetAccessRule("*", EntitySetRights.All);
     config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

    // TODO: set service behavior configuration options
    // Examples:
    // config.DataServiceBehavior.AcceptCountRequests = true;
    // config.DataServiceBehavior.AcceptProjectionRequests = true;
    config.DataServiceBehavior.MaxProtocolVersion = System.Data.Services.Common.DataServiceProtocolVersion.V2;
}

The data service is now created. To test this, run the project and navigate to the nw.svc file. You should see a listing as shown below that outlines all the entry points to the data service. If you don’t, tweak your IE settings and reload.

image

Step 2: Enable data binding on the client.

By default, the client side types generated by ADO.NET Data Services v1.5 CTP2 do not implement binding interfaces. To get client side types that do implement the binding interfaces, you have to tell the code generation library that you want client code that has binding enabled. To do this, set an environment variable before starting Visual Studio and then use Add Service Reference (ASR) to generate client proxy code. The environment variables to set are:

set dscodegen_usedsc=1

set dscodegen_version=2.0

Note: The use of this environment variable is further explained by the video embedded in this blog post.

Note: It is also possible to generate proxy code that have binding enabled using DataSvcUtil.exe with the /DataServiceCollection and /Version flag.

image

Step 3: Create client proxy code with binding enabled.

After setting the environment variable in step 2, open the solution you created in step 1 and create a new WPF project.

image

Once you have created a WPF client project, the next step is to generate client side types. To do this, find the DatabindingClient project in the solution explorer, right-click the project and select Add Service Reference... In the Add Service Reference dialog, click the Discover button. The Northwind.svc service will show up in the Service window. Enter NorthwindService as the Namespace value and select OK. This wizard will generate a set of client side types that can be used to interact with the service created in step 1.

image

You will now see a new NorthwindService node under the Service References Node in the solution explorer. As well, you will see a reference to Microsoft.Data.Services.Client in the references node; if you do not see the reference to Microsoft.Data.Services.Client or you see a reference to System.Data.Services.Client go to the ADO.NET Data Services blog and read this post about enabling ADO.NET Data Services v1.5 features in Visual Studio and then repeat the Add Service Reference Step.

image

The next part of this step is to create a new instance of the ADO.NET Data Services client context and connect to the service created in step 1. To do this, add the following code to the Window1.xaml.cs file to create a connection to the service; making sure to replace the host and port number with the values for your service.

public partial class Window1 : Window
{
    NorthwindEntities nwsvc = new NorthwindEntities(new Uri("http://localhost:52002/Northwind.svc/"));

    
    public Window1()
    {
        InitializeComponent();

    }
}

The next step is to create an interface that you can bind the result of a query to. The service you created in step 1 exposes a set of Suppliers and a set of Products from the Northwind database with a one-to-many relationship between them. The XAML code below will create two listviews, one to display the suppliers and another to display the products associated with the current supplier selected in the first view. This type of binding is called master-detail binding.

The code below uses standard WPF binding semantics. The ItemsSource of the supplierView is set to “{Binding}”, this will cause the listview to bind to the collection of items that are supplied as the data context of the supplierView; in this case the collection of items will be a collection of supplier objects. The columns of the supplierView are each bound to a property of the supplier object through the DisplayMemberBinding="{Binding Path=SupplierID}"/> tag.

The second listview, productsView, is bound to the Products property of the supplier objects by the ItemsSource="{Binding Products}" tag.

By supplying the IsSynchronizedWithCurrentItem="True" tag on the listview, you are taking advantage of the feature WPF has to automatically display the items in the second list view (products) that are associated with the currently selected item in the first list view (suppliers).

Paste the following code snippet into the window1.xaml file:

<Grid Name="productViewGrid">
    <ListView ItemsSource="{Binding}" Margin="25,11,33,145" Name="supplierView" IsSynchronizedWithCurrentItem="True">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Path=SupplierID}"/>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=CompanyName}"/>
                <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Path=Address}"/>
                <GridViewColumn Header="City" DisplayMemberBinding="{Binding Path=City}"/>
                <GridViewColumn Header="Region" DisplayMemberBinding="{Binding Path=Region}"/>
            </GridView>
        </ListView.View>
    </ListView>
    <ListView Margin="25,0,33,12" Name="productsView" ItemsSource="{Binding Products}" IsSynchronizedWithCurrentItem="True" Height="117" VerticalAlignment="Bottom" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ProductID}"/>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding ProductName}"/>
                <GridViewColumn Header="QuantityPerUnit" DisplayMemberBinding="{Binding QuantityPerUnit}"/>
                <GridViewColumn Header="Price" DisplayMemberBinding="{Binding UnitPrice}"/>
                <GridViewColumn Header="InStock" DisplayMemberBinding="{Binding UnitsInStock}"/>
            </GridView>
        </ListView.View>
    </ListView>
</
Grid>


Edit the following attributes of your window: Height="382" Width="584" to properly display the controls.

This will create a WPF interface that looks like this:

image

The final step to enable binding to these WPF controls is to set the DataContext of the grid in the window you just created to the result of a query for suppliers from the service created in step 1. This is done by executing a standard ADO.NET Data Services query on the context for the set of suppliers and then loading the result of the query into a DataServiceCollection. To do this, add the following code to the constructor for the window:

public Window1()
{
    InitializeComponent();
    this.productViewGrid.DataContext =
        DataServiceCollection.CreateTracked<Suppliers>(nwsvc,
                   nwsvc.Suppliers.Expand("Products")
                );
}

Once this is complete, compile the project and run it. The result should be:

image

Step 4: Two-way Binding

Up to this point in the walkthrough, you have set up a service, created a WPF client and bound the result of a query to the service to a pair of listview controls in the client. This type of binding you have done so far has all been one-way binding. The DataServiceCollection you used at the end of step 3 also supports two-way binding. This means that any changes made to the collection or items in the collection will propagate to the service when a call to SaveChanges() is made on the context.

This final step will walk you through adding buttons that will add items to the collection of products and take advantage of two-way binding to have those changes propagate to the service and the backing northwind database.

To start, add the following XAML code to the window1.xaml file to create buttons to that will add a product from the list of products and save the changes to the service.

<Button Height="24" HorizontalAlignment="Right" Margin="0,0,89,4" Name="addButton" VerticalAlignment="Bottom" Width="28" Click="addButton_Click">+</Button>
<
Button Height="24" HorizontalAlignment="Right" Margin="0,0,33,4" Name="saveButton" VerticalAlignment="Bottom" Width="50" Click="saveButton_Click">Save</Button>

The next step is to handle the click events on the new buttons and add the currently select product in the list. The first thing we will need is a new product window to input the property values of a new product when one is created. To do this, create a new WPF window in your client project called ProductWindow.

image

After creating the window, we need to set up the product window to bind to a single instance of the product class. To configure binding in the product window, you will use the same WPF binding method you used for the supplier window, except this window will bind to a single object and not a collection of objects. Add the following XAML code into the ProductWindow.xaml:

<Grid x:Name="productGrid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="171*" />
        <ColumnDefinition Width="159*" />
    </Grid.ColumnDefinitions>
    <Label Height="26" Margin="12,17,68,0" Name="nameLabel" VerticalAlignment="Top">Name:</Label>
    <Label Margin="12,49,6,0" Name="quantityLabel" Height="26" VerticalAlignment="Top">Quantity Per Unit:</Label>
    <Label Margin="12,78,68,64" Name="priceLabel">Price:</Label>
    <Label Height="26" Margin="12,0,68,35" Name="inStockLabel" VerticalAlignment="Bottom">InStock:</Label>
    <TextBox Height="23" Margin="0,23,28.018,0" Name="nameTextBox" VerticalAlignment="Top" Text="{Binding ProductName}" Grid.Column="1" />
    <TextBox Margin="0,52,28.018,0" Name="quantityTextBox" Text="{Binding QuantityPerUnit}" Height="23" VerticalAlignment="Top" Grid.Column="1" />
    <TextBox Margin="0,81,28.018,64" Name="priceTextBox" Text="{Binding UnitPrice}" Grid.Column="1" />
    <TextBox Height="23" Margin="0,0,28.018,35" Name="inStockTextBox" VerticalAlignment="Bottom" Text="{Binding UnitsInStock}" Grid.Column="1" />
    <Button Height="23" Margin="19.018,0,61,6" Name="okButton" VerticalAlignment="Bottom" Grid.Column="1" Click="okButton_Click">OK</Button>
</
Grid>

Set the height of the product window to 206 and the width to 296. Next add the following code to the ProductWindow.xaml.cs file to set the data context to a single product and handle the ok button click event. The click event will add the newly created product to the current suppliers list of products.

public partial class ProductWindow : Window
{
    Suppliers curSupplier;
    Products newProduct;
    public ProductWindow(Products p, Suppliers s)
    {
        InitializeComponent();
        this.productGrid.DataContext = p;
        curSupplier = s;
        newProduct = p;
    }

    private void okButton_Click(object sender, RoutedEventArgs e)
    {
        curSupplier.Products.Add(newProduct);
        this.Close();
    }
}

The final step is to handle the add and save button click events in the supplier window. Add the following code to the Window1.xaml.cs file.

Add the following code to the addButton_Click event to create a new product when the add button is selected. The code creates a new Product and creates a new product window for the user to input the property values for the new product .

private void addButton_Click(object sender, RoutedEventArgs e)
{
    Suppliers supplier = this.supplierView.SelectedItem as Suppliers;
    Products product = new Products();
    ProductWindow win = new ProductWindow(product, supplier);
    win.Show();
}

Add the following code to handle the save button click. This button calls SaveChanges on the context which will cause any operations that have been performed on the context to be sent to the service.

private void saveButton_Click(object sender, RoutedEventArgs e)
{
    nwsvc.SaveChanges();
}

Your project is now complete. You can run the form and use the buttons to add items from the collection of products. When you make a change you then click the save button to persist the changes to the service.

Providing Feedback

We have created a new forum dedicated to providing feedback on "pre-release" versions of data services such as this CTP.  Please direct all your questions and comments about this feature this new forum which is available at: (http://social.msdn.microsoft.com/Forums/en-US/dataservices/threads). 

Note: The forum intended for questions on currently shipping versions of ADO.NET Data Services is still available at: (http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/threads/ )

We look forward to hearing your feedback.

 

Shayne Burgess

ADO.NET Data Services, Program Manager

ADO.NET Data Services v1.5 CTP2 – Projections Overview (Server)
01 September 09 10:48 AM | dpblogs | 1 Comments   

This blog post is an introduction to the projection server capabilities we have added in the ADO Data Services v1.5 CTP2 release.

Introduction to Projections

Beginning in the ADO.NET Data Services v1.5 CTP2 release, the ADO.NET Data Services URI format has been extended to express narrowing projections. In particular, the projections feature allows you to work with a subset of an entity’s properties. This CTP release includes support for both the server and client (.NET only in this CTP, but Silverlight support is coming soon) runtimes. In this post, we’ll walk through how to get started using the new server side projections support using the ADO.NET Data Services URI format. In subsequent posts, we’ll take a look at the support for projections in the client library as well as how data round trips between the client and server when using projections.

The projections feature allows clients to address only the relevant properties to a specific request. By only requesting the applicable subset of an entity’s properties for a particular query, client applications can optimize for bandwidth consumption and memory footprint more effectively by fine tuning the payloads across various application scenarios.

The Projections feature extends the ADO.NET Data Services URI format by adding the $select query option to enable clients to explicitly define the properties to be returned. The $select query option may be used to reduce entity size by explicitly selecting primitive, complex type, and navigation properties on the given entity set. For example, the following usage of $select will only include the CustomerID and ContactName properties of the entities in the Customers entity set.

nw.svc/Customers?$select=CustomerID,ContactName

Walkthrough

The following is a walkthrough of using the projections feature on a data service.

To get started, you'll want to download all of the required software I use in the walkthrough: 

· Visual Studio 2008 SP1 (here)

· ADO.NET Data Services v1.5 CTP2 (here)

First, within Visual Studio create a new web application project (named ProjectionsDemo).

clip_image001

Our first data access related task is to generate the Entity Framework-based data access layer to the Northwind database.  Right click the ASP.NET project and select 'Add New Item', then select 'ADO.NET Entity Data Model'.  Name the new item nw.edmx:

clip_image002

After clicking ‘Add’ on the screen above, a wizard will open to walk you through creating the Entity Data Model for the Northwind database. Use the default settings until you get to the point where you choose the database objects to include in the model. For this demo, choose only the Customers, Orders, Order Details, and Products tables.

clip_image003

Once you reach the ‘Choose Your Database Objects’ screen, select the two tables and click ‘Finish’. This will open the Entity Data Model designer view.  This view allows you to customize the generated conceptual data model. To learn more about the mapping capabilities of the Entity Framework, see here. For this demo rename the Customers, Orders, Order_Details, and Products entities to Customer, Order, OrderDetail, and Product. Then, rename the entity sets to Customers, Orders, OrderDetails, and Products. Lastly, rename the Order_Details navigation properties on the Order and Product entity types to OrderDetails. The resulting model should look like the following diagram.

clip_image004

Create a v1.5 CTP2-based ADO.NET Data Service over this model. To create the data service, right click the ASP.NET project and select 'Add New Item'.  Add an 'ADO.NET Data Service v1.5 CTP2' item called nw.svc.

clip_image005

This will generate a file (nw.svc.cs) which represents the skeleton of a v1.5 data service. Next, we need to point the data service at the data model to be exposed as a REST-service and enable the projections feature. The snippet below shows this initialization. One thing to note is that a data service is locked down by default, so we need to take explicit steps to open access to it. For this simple application we’ll enable read and write access to the entire model quickly using the call to ‘SetEntitySetAccessRule’ shown below. Then, we enable projections by setting AcceptProjectionRequests to true, and enabling the V2 protocol. Note, when enabling projections as shown below, enabling the V2 protocol is required whereas setting AcceptProjectionRequests is optional as it is set to true by default.

clip_image006

The data service is now created. To test this, run the project and navigate to the nw.svc file. You should see a listing as shown below that outlines all the entry points to the data service. If you don’t, update IE’s settings and reload.

clip_image007

Now, let’s try our first projection over the Customers entity set on the nw.svc data service. For primitive and complex type properties, a selection of a particular property will cause its value to be included in the response. For example, to include only the CustomerID and ContactName properties for the Customers entity set, the following may be used:

nw.svc/Customers?$select=CustomerID,ContactName

clip_image008

As shown in the response above, only the CustomerID and ContactName properties are returned across the Customers entity set. In general, a query that does not include usage of $select identifies all the data to be returned whereas $select simply narrows that result.

The equivalent response in JSON for the first entry for the query above is also shown below:

{"d" : [
    {
        "__metadata": {
            "uri": "http://127.0.0.1:42218/nw.svc/Customers(\'ALFKI\')", "type": "NorthwindModel.Customer"
        },
        "CustomerID": "ALFKI",
        "ContactName": "Mary Anders"
    }
]}
Complex type properties may also be selected using the select query option.  For example, if your model contained a complex Address type that defines a Street, City, and Zip, to select the CustomerID and Address complex type, the query below may be used. When complex types are selected, all properties defined on that complex type property are returned. As a result, this query returns all components of the complex Address type: Street, City, and Zip.

nw.svc/Customers?$select=CustomerID,Address

The select option also enables the projection of navigation properties. Selecting a navigation property causes the link to the corresponding entity (or entity set) to be included in the result set. For example, the following query will result in a selection of the CustomerID property in addition to a link to the collection of order entities for each customer.

nw.svc/Customers?$select=CustomerID,Orders

clip_image009

For the Orders property referenced in the above query, the select option above will only output a link to the corresponding entity set. However, if related entities are expanded underneath the selected navigation property, all expanded descendants will be included in the response for the selected navigation property. For example, the following will select the CustomerID as well as the Orders property with fully expanded Orders and OrderDetails inlined within the response.

nw.svc/Customers?$select=CustomerID,Orders&$expand=Orders/OrderDetails&$top=3

clip_image010

When using the $select query operator with navigation properties, individual properties of the defining entity type for that navigation property may be selected as well. For example, the following query will select the CustomerID on the Customers entity set with inlined Orders that only include the OrderID property.

nw.svc/Customers?$select=CustomerID,Orders/OrderID&$expand=Orders&$top=3

The $select query option also introduces the * syntax for including all properties on a given entity or entity set. This syntax may be used to reference all properties of the current top level entity (or entity set) or all properties of a navigation property. In other words, the * syntax causes all entity data to be included without traversing associations. For example, the following select option includes all properties of each customer entity.

nw.svc/Customers?$select=*

clip_image011

The * selection may also be used on navigational properties to include all properties defined for the entity or entities associated with a navigation property. For example, the following query includes the CustomerID property of the top level Customer entity set as well as Order entities with all properties listed.

nw.svc/Customers?$select=CustomerID,Orders/*&$expand=Orders&$top=3

It is important to note that the * selection does not traverse associations. In other words, if related entities have been expanded underneath a path that uses *, the usage of * will not cause the expanded entities underneath this path to be included. For example, the following query is equivalent to the query above in that the CustomerID is included and Order entities with all properties are included; however, rather than including the fully expanded OrderDetail entities referenced in the expand clause below, each Order will contain an OrderDetails property link that references the corresponding OrderDetails entity set.

nw.svc/Customers?$select=CustomerID,Orders/*&$expand=Orders/OrderDetails&$top=3

Lastly, if a feed has customizable feed mappings, usage of $select will not impact those mappings. In other words, $select only impacts <content> and <link> content and does not impact property values mapped to other aspects of the feed.

We’ve now completed our tour of using the new projections feature on the server to work with a subset of an entity’s properties. By using the new $select query operator to request only the applicable subset of an entity’s properties for a particular query, our client applications can now more effectively optimize for bandwidth consumption and memory footprint. In subsequent posts, we’ll take a look at the support for projections in the client library as well as how data round trips between the client and server when using projections.

Aaron Dunnington

ADO.NET Data Services, Program Manager

Customizable Feed Support in CTP2
01 September 09 08:24 AM | dpblogs | 0 Comments   

Phani, a data services team member, has updated his three part series on Customizable Feeds (aka. “Web Friendly Feeds”) for the ADO.NET Data Services v1.5 CTP2 release.  Check out his updated series here:

Introducing Web Friendly Feeds aka Friendly Feeds (Updated for CTP2)

ADO.NET Data Services Friendly Feeds , Mapping EDM Types – I

ADO.NET Data Services Friendly Feeds , Mapping CLR Types

 

-Mike Flasko

ADO.NET Data Services, Program Manager

ADO.NET Data Services v1.5 CTP2 – Now Available for Download
31 August 09 02:44 PM | dpblogs | 11 Comments   

CTP2 of our ADO.NET Data Services v1.5 release is now available for download here.  ADO.NET Data Services v1.5 CTP2 is the second tech preview release of the next version of ADO.NET Data Services.  This release (v1.5) will target the .NET Framework 3.5 SP1 & Silverlight 3 platforms and provide new client and server side features for data service developers.  In addition, the features included in this release (v1.5) will be part of the .NET Framework 4 release. 

What’s included in CTP2?

This release includes updates to the features that were in the CTP1 release of ADO.NET Data Services v1.5 plus a few additional new features and a number of bug fixes.  The features included in this CTP are:

· Projections: This ADO.NET Data Services URI format has been extended to express projections (i.e. you can now work with a subset of the properties of an entity).  This CTP includes both server and client library (including LINQ support) support for projections.  We’ve done a fair amount of work in this space to support roundtripping projected values, working with anonymous types, etc.  We’ll create a subsequent series of posts to describe this feature.  

o Changes since CTP1: This feature is new in this CTP

· Data Binding:  The data services client library for the .NET Framework 3.5 SP1 and Silverlight2 has been extended to support two-way data binding for WPF and Silverlight based applications. 

o Changes since CTP1: We’ve cleaned up the types (e.g. DataServiceCollection class) introduced in CTP1 to make data binding simple with ADO.NET Data Services

· Row Count: One scenario we heard a ton of feedback on after shipping V1 of ADO.NET Data Services in the .NET Framework 3.5SP1 is the ability for the a client of a data service to determine the total number of entities in a set without having to retrieve them all.  To address this need, we have extended the data services addressing scheme to allow a client to obtain this type of information without having to download all the entities in a set.

o Changes since CTP1:  Bug fixes, APIs are the same as in CTP1

· Feed Customization (aka "Web Friendly Feeds"): A common ask we have received is to provide the ability to customize how entities are mapped into the various elements of an AtomPub feed.  This feature does just that by providing a data service author declarative control over how the data service runtime maps the properties of an entity (e.g. a Customer, Order, etc) to the elements of a feed.

o Changes since CTP1: We extended the number of Atom elements which entity properties can be mapped to.  We have also renamed each of the attributes used to customize feeds.  We’ll post an updated blog series on this topic in the coming days to describe the changes in detail.

· Server Driven Paging (SDP): This one is best described by example.  If you had a data service that exposes photos, you likely want to limit the total number of photos a single request to the service can retrieve because the total collection of photos may be very large.  This feature allows a service author to set per collection limits on the total number of entities returned for each request.  In addition to limiting the number of photos returned per request, the server provides the client a "next link" which is simply a URI specifying how to continue retrieving the rest of the entities in the collection not returned by the first request.  For those familiar with AtomPub, this feature adds support for AtomPub <link rel="next" ...> elements to the data service runtime.  

o Changes since CTP1:  This CTP adds client library (.NET & Silverlight3) support for SDP

· Enhanced BLOB Support: This feature enhances the BLOB support provided in V1 to enable data services to stream arbitrarily large BLOBs, store binary content separate from its metadata, easily defer the loading of BLOB content when its metadata is requested, etc. 

o Changes since CTP1: This CTP adds client library (.NET & Silverlight3) support for BLOBs.  Server support was included in CTP1

· Request Pipeline: We have started to expose events throughout the data services server request processing pipeline.  For this release we’ll expose request level events and in future we’ll look to expose more fine grained events based on your feedback.  The goal of exposing our processing pipeline is to allow services further transparency into a data service such that a service author can do things such as setting HTTP response cache headers, wrapping interceptor processing and data service request processing in a single transaction, etc.   

o Changes since CTP1: This feature is new in this CTP

· New "Data Service Provider" Interface for Custom Provider Writers: As the data services runtime has evolved, so has the number of ways people want to plug data into the data service framework.  In V1, two methods (Entity Framework and arbitrary .NET classes) were supported to enable a data service to interact with various diverse data sources.  To address another class of environments and data sources we have introduced a way to write a "custom" provider for those cases when the previous two provider models don't meet your needs.

o Changes since CTP1: In addition to adding a few new provider interfaces, this CTP has renamed & refactored a number of the provider interfaces introduced in this release.  Stay tuned for a follow up blog post that describes what interfaces are available and their purpose.  

· Bug Fixes: This release builds on the code base shipped in CTP1 and incorporates all fixes we have made to this point.

Getting Started

To get started with the v1.5 CTP2 bits, check out the basic "getting started" video below.  The video walks through how to configure VS support for the release and how to get a very simple “hello world” project up and running quickly.  NOTE: double click the screen to open the video in full screen mode.

CTP2 Frequently Asked Questions

Q1: What are the prerequisites?

A1: See the CTP2 download center page here for a list of prerequisites, supported operating systems, etc?

Q2: Does CTP2 install side-by-side with what is currently on my development machine?

A2: By in large this install is side-by-side with existing VS 2008 SP1 and .NET Fx 3.5SP1 bits; however, that was not possible in all cases so some .NET and VS files will be modified by the CTP2 installer.  The files should be replaced to their original state during uninstall of this CTP.  CTP2 does NOT install side-by-side with CTP1 of ADO.NET Data Services v1.5.  The CTP2 installer will require you to first uninstall CTP1.

Q3: Why does the CTP2 download page include two installers?

A3: This CTP includes a “full” (runtime & tools) and a “runtime only” installer.  The “full” installer will install all required runtime assemblies as well update your VS2008 SP1 environment to work with the CTP.  The “runtime only” installer will install all the data services runtime assemblies as well as a command line tool (datasvcutil.exe) into the CTP2 directory.  No visual studio integration will be installed by the “runtime only” installer.  Having two installers is a temporary solution (for this CTP only) to allow us to get this CTP out as soon as possible.  In future we will have a single installer for the release.

Q4: Does this CTP work on Windows 7?

A4: This release supports Windows 7.  The CTP2 “full” installer (see Q3 above) will only install the runtime components on Windows 7.   If you wish to get the “full” experience on Windows 7, then you can follow steps similar  to those described by Shawn Wildermuth here (note: his post was for CTP1 of data services, but they should apply to CTP2, just be sure to look for the CTP2 directory, instead of the CTP1 directory). 

Giving Feedback

The following forum is dedicated to providing feedback on "pre-release" versions of data services such as this CTP: http://social.msdn.microsoft.com/Forums/en-US/dataservices/threads.  Please direct all your questions about the release to this forum. 

Note: The forum intended for questions on currently shipping versions of ADO.NET Data Services is still available at: (http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/threads/ )

We look forward to hearing your thoughts on the release!

-Mike Flasko

ADO.NET Data Services, Program Manager

Announcing the PHP Toolkit for ADO.NET Data Services
21 August 09 08:57 AM | dpblogs | 1 Comments   

This morning the Microsoft Interoperability team announced the release of a new project that bridges PHP and.NET: the PHP Toolkit for ADO.NET Data Services. The toolkit makes it easier for PHP developers to connect to and take advantage of services built using ADO.NET Data Services. The PHP Toolkit for ADO.NET Data Services is an open source project funded by Microsoft and developed by Persistent Systems and is available today on Codeplex at phpdataservices.codeplex.com

You can see an overview and quick demo of the toolkit in the Channel9 video with Pablo Castro and Claudio Caldato, Senior Program Manager with the Interoperability Technical Strategy team.

For more information on the toolkit check out the Interoperability Teams blog post and phpdataservices.codeplex.com.

- Elisa Flasko
Program Manager, Data Programmability

More Posts Next page »

Search

This Blog

Syndication

Page view tracker