Working with Data on Windows Phone 7 – Part 2

In this part I am going to use WCF Data Services (formerly known as project Astoria and ADO.NET Data Services) to accomplish the same couple of tasks I did in WCF custom service.  I am going to get a list of people and add a person.

I will use exact same project as I did the last time.  As you recall, I created a database with one table using EF Code First.  This is where I am going to start.  In first step I am going to create an Entity Framework model from that database.  To do so, I am going to add new item to my web project and select Entity Framework model.

image

I will then walk through EF model wizard to generate the model from my database:

image

image

 

image

This will generate my model with my person class.

WCF Data Service will expose my model via web RESTful interfaces.  To add the service, I am going to add new item again, but now select WCF Data Service as item type:

 

image

Next step is to configure WCF Data Service to use my entity model.  This step is pretty easy, since service is a generic type with a parameter that takes entity model

    public class PersonWcfDataService : DataService<PersonsDbEntities>
    {
       
public static void InitializeService(DataServiceConfiguration
config)
        {
            config.SetEntitySetAccessRule(
"*", EntitySetRights
.All);
            config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
        }
    }

 

In the code above I am setting rights to all entities to everyone.  In production I would not do this, but it works as illustration.  In my next step I am going to test the service.  I am going to right click on PersonWcfDataService.svc file that was generated in the step above and select View In Browser.

image

Next, I want to make sure I can get the list of people.  I am going to change my Url and test that.  You can see the address and result below:

image

Of course the results look like Atom feed since OData that WCF Data Service implement extends AtomPub protocol.  I can look at the data by selecting view source.  The data looks as following:

image

Next I need to generate proxy for my Phone application.  Unfortunately, add service reference does not work for phone Silverlight applications.  So, I am going to download necessary files from CodePlex to proceed.

Visit http://odata.codeplex.com and download ODataClient_BinariesAndCodeGenToolForWinPhone.zip.  Once it is on your local machine, unblock the zip file in windows properties, otherwise you will get compilation errors later.  Unzip it into a blank folder to make it easy to find later.

Here is the content of the folder:

image

Add a reference to System.Data.Services.Client.dll to your windows phone project.  Now, we need to generate proxy and related classes.  To do so we will use DataSvcUtil.exe from the same folder.  Here is the command line I am using:

 

datasvcutil /uri:http://localhost:50406/PersonWcfDataService.svc/ /out:.PersonModel.cs /DataServiceCollection /Version:2.0

As you can see I am providing my svc file’s url.  I am using version 2 of the data services.  I am outputting the proxy into PersonModel.cs file.  DataServiceCollection parameter instructs the utility to generate collections that derive from DataSericeCollection.  Next I am include this file in my project.

Next I am going to create an instance of the client in my view model as following:

PersonsDbEntities odataClient;

odataClient =

         new PersonsDbEntities(new Uri(@"http://localhost:50406/PersonWcfDataService.svc"));

 

Of course in production you need to give correct Url.  Next, I am going to query the data.  First I am going to define a property to hold my collection


        private DataServiceCollection<PersonsDbModel.Person> oDataPeople;
 
       
public DataServiceCollection<PersonsDbModel.Person
> ODataPeople
        {
           
get { return
oDataPeople; }
           
set
            {
                oDataPeople =
value
;
                NotifyPropertyChanged(
"ODataPeople");
            }
        }

 

Then I am going to query the data as following

            ODataPeople = new DataServiceCollection<PersonsDbModel.Person>(odataClient);
            ODataPeople.LoadCompleted += ODataPeople_LoadCompleted;
 
           
try
            {
                ODataPeople.LoadAsync(peopleUri);
            }
           
catch (DataServiceClientException
ex)
            {
               
MessageBox.Show(ex.ToString());
            }

 

So, first I create a collection and tie it to my client.  Without that I can query the collection.  In the callback I check for errors:

        void ODataPeople_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
           
if (e.QueryOperationResponse.Error != null
)
            {
               
MessageBox.Show(e.QueryOperationResponse.Error.ToString());
            }
        }

 

That I it.  Now I just add a listbox to my UI and bind it to this collection:

            <controls:PivotItem Header="oData">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="ODataListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding ODataPeople}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432">
                                <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Next, adding a person via OData.  It is really simple.  I just add new person to my collection and start the save process.  DataSericeCollection  objects are smart to keep track of the changes that occur during operation on the server.


        public void InsertPersonOdata()
        {
            ODataPeople.Add(
new PersonsDbModel.Person() { FirstName = "James", LastName = "Homer", PersonID = Guid
.NewGuid() });
            odataClient.BeginSaveChanges(
SaveChangesOptions
.Batch, (ar) =>
            {
               
Deployment
.Current.Dispatcher.BeginInvoke(() =>
                {
                    odataClient = ar.AsyncState
as PersonsDbModel.PersonsDbEntities
;
                   
DataServiceResponse
response = odataClient.EndSaveChanges(ar);
                   
if
(response.IsBatchResponse)
                    {
                       
StringBuilder errors = new StringBuilder
();
                       
foreach (ChangeOperationResponse change in
response)
                        {
                           
if (change.Error != null
)
                            {
                                errors.Append(change.Error.ToString());
                            }
                        }
                       
if
(errors.Length == 0)
                        {
                           
MessageBox.Show("Success"
);
                        }
                       
else
                        {
                           
MessageBox.Show(errors.ToString());
                        }
                    }
                });
            }, odataClient);
        }

 

You can download the entire solution for both parts 1 and 2 here.  There does seem to be some flakiness in running both services from one solution, so you may have to comment WCF Service or OData service calls to test each portion.

Leave a Reply

Your email address will not be published. Required fields are marked *