Entity Framework Code-First, oData & Windows Phone Client

Entity Framework Code-First is the coolest thing since sliced bread, Windows  Phone is the hottest thing since Tickle-Me-Elmo and oData is just too great to ignore.

As part of the Full Stack project, we wanted to put them together, which turns out to be pretty easy… once you know how.

EF Code-First CTP5 is available now and there should be very few breaking changes in the release edition, which is due early in 2011.

Note: EF Code-First evolved rapidly and many of the existing documents and blog posts which were written with earlier versions, may now be obsolete or at least misleading.

Code-First?

With traditional Entity Framework you start with a database and from that you generate “entities” – classes that bridge between the relational database and your object oriented program.

With Code-First (Magic-Unicorn) (see Hanselman’s write up and this later write up by Scott Guthrie) the Entity Framework looks at classes you created and says “if I had created these classes, the database would have to have looked like this…” and creates the database for you! By deriving your entity collections from DbSet and exposing them via a class that derives from DbContext, you “turn on” database backing for your POCO with a minimum of code and no hidden designer or configuration files.

POCO == Plain Old CLR Objects

Your entity objects can be used throughout your applications – in web applications, console applications, Silverlight and Windows Phone applications, etc. In our case, we’ll want to read and update data from a Windows Phone client application, so we’ll expose the entities through a DataService and hook the Windows Phone client application to that data via proxies.  Piece of Pie.  Easy as cake.

The Demo Architecture

To see this at work, we’ll create an ASP.NET/MVC application which will act as the host for our Data Service.  We’ll create an incredibly simple data layer using EF Code-First on top of SQLCE4 and we’ll expose the data in a WCF Data Service using the oData protocol.  Our Windows Phone 7 client will instantiate  the data context via a URI and load the data asynchronously.

Setting up the Server project with MVC 3, EF Code First, and SQL CE 4

Create a new application of type ASP.NET MVC 3 and name it DeadSimpleServer.

We need to add the latest SQLCE4 and Entity Framework Code First CTP’s to our project. Fortunately, NuGet makes that really easy. Open the Package Manager Console (View / Other Windows / Package Manager Console) and type in “Install-Package EFCodeFirst.SqlServerCompact” at the PM> command prompt. Since NuGet handles dependencies for you, you’ll see that it installs everything you need to use Entity Framework Code First in your project.

PM> install-package EFCodeFirst.SqlServerCompact
'SQLCE (? 4.0.8435.1)' not installed. Attempting to retrieve dependency from source...
Done
'EFCodeFirst (? 0.8)' not installed. Attempting to retrieve dependency from source...
Done
'WebActivator (? 1.0.0.0)' not installed. Attempting to retrieve dependency from source...
Done
You are downloading SQLCE from Microsoft, the license agreement to which is available at http://173.203.67.148/licenses/SQLCE/EULA_ENU.rtf. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'SQLCE 4.0.8435.1'
You are downloading EFCodeFirst from Microsoft, the license agreement to which is available at http://go.microsoft.com/fwlink/?LinkID=206497. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'EFCodeFirst 0.8'
Successfully installed 'WebActivator 1.0.0.0'
You are downloading EFCodeFirst.SqlServerCompact from Microsoft, the license agreement to which is available at http://173.203.67.148/licenses/SQLCE/EULA_ENU.rtf. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'EFCodeFirst.SqlServerCompact 0.8'
Successfully added 'SQLCE 4.0.8435.1' to EfCodeFirst-CTP5
Successfully added 'EFCodeFirst 0.8' to EfCodeFirst-CTP5
Successfully added 'WebActivator 1.0.0.0' to EfCodeFirst-CTP5
Successfully added 'EFCodeFirst.SqlServerCompact 0.8' to EfCodeFirst-CTP5

Note: We’re using SQLCE 4 with Entity Framework here because they work really well together from a development scenario, but you can of course use Entity Framework Code First with other databases supported by Entity framework.

Creating The Model using EF Code First

Now we can create our model class. Right-click the Models folder and select Add/Class. Name the Class Person.cs and add the following code:

using System.Data.Entity;

namespace DeadSimpleServer.Models
{
   public class Person
   {
      public int ID { get; set; }
      public string Name { get; set; }
   }

   public class PersonContext : DbContext
   {
      public DbSet<Person> People { get; set; }
   }
}

Notice that the entity class Person has no special interfaces or base class. There’s nothing special needed to make it work – it’s just a POCO. The context we’ll use to access the entities in the application is called PersonContext, but you could name it anything you wanted. The important thing is that it inherits DbContext and contains one or more DbSet which holds our entity collections.

Adding Seed Data

We need some testing data to expose from our service. The simplest way to get that into our database is to modify the CreateCeDatabaseIfNotExists class in AppStart_SQLCEEntityFramework.cs by adding some seed data to the Seed method:

protected virtual void Seed( TContext context )
{
   var personContext = context as PersonContext;
   personContext.People.Add( new Person { ID = 1, Name = "George Washington" } );
   personContext.People.Add( new Person { ID = 2, Name = "John Adams" } );
   personContext.People.Add( new Person { ID = 3, Name = "Thomas Jefferson" } );
   personContext.SaveChanges();
}

The CreateCeDatabaseIfNotExists class name is pretty self-explanatory – when our DbContext is accessed and the database isn’t found, a new one will be created and populated with the data in the Seed method. There’s one more step to make that work – we need to uncomment a line in the Start method at the top of of the AppStart_SQLCEEntityFramework class and set the context name, as shown here,

public static class AppStart_SQLCEEntityFramework {
    public static void Start() {
        DbDatabase.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");

        // Sets the default database initialization code for working with Sql Server Compact databases
        // Uncomment this line and replace CONTEXT_NAME with the name of your DbContext if you are
        // using your DbContext to create and manage your database
        DbDatabase.SetInitializer(new CreateCeDatabaseIfNotExists<PersonContext>());
    }
}

Now our database and entity framework are set up, so we can expose data via WCF Data Services.

Note: This is a bare-bones implementation with no administration screens. If you’d like to see how those are added, check out The Full Stack screencast series.

Creating the oData Service using WCF Data Services

Add a new WCF Data Service to the project (right-click the project / Add New Item / Web / WCF Data Service).

We’ll be exposing all the data as read/write.  Remember to reconfigure to control and minimize access as appropriate for your own application.

Open the code behind for your service. In our case, the service was called PersonTestDataService.svc so the code behind class file is PersonTestDataService.svc.cs.

using System.Data.Services;
using System.Data.Services.Common;
using System.ServiceModel;
using DeadSimpleServer.Models;

namespace DeadSimpleServer
{
   [ServiceBehavior( IncludeExceptionDetailInFaults = true )]
   public class PersonTestDataService : DataService<PersonContext>
   {
      // This method is called only once to initialize service-wide policies.
      public static void InitializeService( DataServiceConfiguration config )
      {
         config.SetEntitySetAccessRule( "*", EntitySetRights.All );
         config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
         config.UseVerboseErrors = true;
      }
   }
}

We’re enabling a few additional settings to make it easier to debug if you run into trouble. The ServiceBehavior attribute is set to include exception details in faults, and we’re using verbose errors. You can remove both of these when your service is working, as your public production service shouldn’t be revealing exception information.

You can view the output of the service by running the application and browsing to http://localhost:[portnumber]/PersonTestDataService.svc/:

<service xml:base="http://localhost:49786/PersonTestDataService.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
 <workspace>
  <atom:title>Default</atom:title>
   <collection href="People">
    <atom:title>People</atom:title>
   </collection>
  </workspace>
</service>

This indicates that the service exposes one collection, which is accessible by browsing to http://localhost:[portnumber]/PersonTestDataService.svc/People

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<feed xml:base=http://localhost:49786/PersonTestDataService.svc/
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
  <title type="text">People</title>
  <id>http://localhost:49786/PersonTestDataService.svc/People</id>
  <updated>2010-12-29T01:01:50Z</updated>
  <link rel="self" title="People" href="People" />
  <entry>
    <id>http://localhost:49786/PersonTestDataService.svc/People(1)</id>
    <title type="text"></title>
    <updated>2010-12-29T01:01:50Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Person" href="People(1)" />
    <category term="DeadSimpleServer.Models.Person"
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">1</d:ID>
        <d:Name>George Washington</d:Name>
      </m:properties>
    </content>
  </entry>
  <entry>
    ...
  </entry>
</feed>

Let’s recap what we’ve done so far.

Entity Framework Code First, OData, and Windows Phone - Server Side

But enough with services and XML – let’s get this into our Windows Phone client application.

Creating the DataServiceContext for the Client

Use the latest DataSvcUtil.exe from http://odata.codeplex.com. As of today, that’s in this download: http://odata.codeplex.com/releases/view/54698

You need to run it with a few options:

/uri – This will point to the service URI. In this case, it’s http://localhost:59342/PersonTestDataService.svc Pick up the port number from your running server (e.g., the server formerly known as Cassini).

/out – This is the DataServiceContext class that will be generated. You can name it whatever you’d like.

/Version – should be set to 2.0

/DataServiceCollection – Include this flag to generate collections derived from the DataServiceCollection base, which brings in all the ObservableCollection goodness that handles your INotifyPropertyChanged events for you.

Here’s the console session from when we ran it:

E:\WhoIsThatPhone\WhoIsThatPhone> D:\oData\DataSvcUtil.exe
/out:ContactService.cs /Version:2.0 /DataServiceCollection
/uri:http://localhost:59342/PersonTestDataService.svc

Microsoft (R) DataSvcUtil version 1.0.0.0
Copyright (C) 2008 Microsoft Corporation.
All rights reserved.
Writing object layer file...
Generation Complete -- 0 errors, 0 warnings
E:\WhoIsThatPhone\WhoIsThatPhone

This produced the file ContactService.cs in the WhoIsThatPhone directory.

Creating The Win Phone Client Application

Create a new application of type Windows Phone Databound Application.

Modify the Xaml to bind as you would bind to any enumerable source; that is begin by changing the binding on the ItemsSource property of the ListBox from Binding Item to just Binding

ListBox
x:Name="MainListBox"
Margin="0,0,-12,0"
ItemsSource="{Binding}"
SelectionChanged="MainListBox_SelectionChanged"

Next, to keep things simple, change the Binding on the two TextBlocks within the DataTemplate to Name and ID,

 <ListBox
    x:Name="MainListBox"
    Margin="0,0,-12,0"
    ItemsSource="{Binding}"
    SelectionChanged="MainListBox_SelectionChanged">
    <ListBox.ItemTemplate>
       <DataTemplate>
          <StackPanel
             Margin="0,0,0,17"
             Width="432">
             <TextBlock
                Text="{Binding Name}"
                TextWrapping="Wrap"
                Style="{StaticResource PhoneTextExtraLargeStyle}" />
             <TextBlock
                Text="{Binding ID}"
                TextWrapping="Wrap"
                Margin="12,-6,12,0"
                Style="{StaticResource PhoneTextSubtleStyle}" />
          </StackPanel>
       </DataTemplate>
    </ListBox.ItemTemplate>
 </ListBox>

Getting The Context

In the code-behind you’ll first declare a member variable to hold the context from the Entity Framework. This is named using convention over configuration.

The db type is Person and the context is of type PersonContext, You initialize it by providing the URI, in this case using the URL obtained from the Cassini web server,

PersonContext context =
  new PersonContext(
  new Uri( "http://localhost:49786/PersonTestDataService.svc/" ) );

Create a second member variable of type DataServiceCollection<Person> but do not initialize it,

DataServiceCollection<Person> people;

In the constructor you’ll initialize the DataServiceCollection using the PersonContext,

public MainPage()
{
   InitializeComponent();
   people = new DataServiceCollection<Person>( context );

Finally, you’ll load the people collection using the LoadAsync method, passing in the fully specified URI for the People collection in the web service,

 people.LoadAsync(
    new Uri(
    "http://localhost:49786/PersonTestDataService.svc/People" ) );

Note that this method runs asynchronously and when it is finished the people  collection is already populated. Thus, since we didn’t need or want to override any of the behavior we don’t implement the LoadCompleted.

Windows Phone - Databound

You can use the LoadCompleted event if you need to do any other UI updates, but you don’t need to. The final code is as shown below:

using System;
using System.Data.Services.Client;
using System.Windows;
using System.Windows.Controls;
using DeadSimpleServer.Models;
using Microsoft.Phone.Controls;

namespace WindowsPhoneODataTest
{
   public partial class MainPage : PhoneApplicationPage
   {
      PersonContext context = new PersonContext(
        new Uri( "http://localhost:49786/PersonTestDataService.svc/" ) );
      DataServiceCollection<Person> people;

      // Constructor
      public MainPage()
      {
         InitializeComponent();

         // Set the data context of the listbox control to the sample data
         // DataContext = App.ViewModel;
         people = new DataServiceCollection<Person>( context );
         people.LoadAsync(
            new Uri( "http://localhost:49786/PersonTestDataService.svc/People" ) );
         DataContext = people;
         this.Loaded += new RoutedEventHandler( MainPage_Loaded );
      }

      // Handle selection changed on ListBox
      private void MainListBox_SelectionChanged( object sender, SelectionChangedEventArgs e )
      {
         // If selected index is -1 (no selection) do nothing
         if ( MainListBox.SelectedIndex == -1 )
            return;

         // Navigate to the new page
         NavigationService.Navigate(
            new Uri( "/DetailsPage.xaml?selectedItem="
            + MainListBox.SelectedIndex, UriKind.Relative ) );

         // Reset selected index to -1 (no selection)
         MainListBox.SelectedIndex = -1;
      }

      // Load data for the ViewModel Items
      private void MainPage_Loaded( object sender, RoutedEventArgs e )
      {
         if ( !App.ViewModel.IsDataLoaded )
         {
            App.ViewModel.LoadData();
         }
      }
   }
}

With people populated we can set it as the DataContext and run the application; you’ll find that the Name and ID are displayed in the list on the Mainpage. Here’s how the pieces in the client fit together:

Entity Framework Code First, OData, and Windows Phone - Client Side

Complete source code available here

Share

About Jesse Liberty

Jesse Liberty is a Master Consultant for Falafel Software, and has three decades of experience writing and delivering software projects. He is the author of 2 dozen books and multiple Pluralsight courses, and has been a Technical Evangelist for Telerik and for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS.
This entry was posted in Data, Essentials, Full Stack, Mini-Tutorial, Patterns & Skills, Tools and Utilities and tagged , . Bookmark the permalink.

15 Responses to Entity Framework Code-First, oData & Windows Phone Client

  1. 2 says:

    Quality content is the secret to attract the viewers to
    pay a visit the web page, that’s what this website is providing.

  2. Anonymous says:

    Greetings from Idaho! I’m bored to death at work so I decided to browse your blog on my iphone during lunch break. I really like the information you provide here and can’t wait to take
    a look when I get home. I’m amazed at how quick your blog loaded on my mobile .. I’m not even using WIFI, just 3G .
    . Anyways, amazing site!

    Also visit my blog … Rapid Opiate Detox (J

  3. Hello! This is my first visit to your blog! We are a team of
    volunteers and starting a new initiative in a community in the
    same niche. Your blog provided us valuable information to work on.
    You have done a wonderful job!

  4. Larry Q says:

    Jesse’s right in his disclaimer about EF Code first and SQL CE changing since he first wrote this.

    I just built an ASP.Net MVC3 site and added the appropriate NuGet packages as he described, but no AppStart_SQLCEEntityFramework class was auto-generated. I had to do it by hand, using the file below as a template. I put the class file into my web’s root folder:

    https://github.com/motowilliams/AppHarborMotoWilliams/blob/a6cb7175c6a8aef58a339d33cc4ee04ec01f611f/AppStart_SQLCEEntityFramework.cs

    In this case you’ll want to change the code from ‘MotorcycleContext’ to ‘PersonContext’, as well as change ‘DbDatabase’ to ‘Database’ since that class name changed after the CTP. In addition, change the ‘using System.Data.Entity.Database’ line at top to read ‘System.Data.Entity’, another post-CTP change.

    Strange, but I can’t download the sample code from Jon Galloway’s skydrive site– I can see the zip file but can’t download it. Skydrive doesn’t give any errors but the file won’t come down. I’ve tried it on a couple of different computers.

    • Larry Q says:

      Some other changes since Jesse originally posted the article that you’ll need to be aware of:

      Calling DataSvcUtil.exe generates the ContractService.cs file as described, but make sure you add it to the windows phone project and not the ASP.Net MVC project– I made that mistake.

      Also, the Windows Phone project will need to have a reference added to the System.Data.Service.Client assembly in order to work with the ContractService.cs file.

      Finally, Microsoft changed the game with regard to the assembly name the DataServiceCollection class lives. It’s now in the System.Data.Service.Client assembly, and not System.Data.Service.Common, as in the MainPage.xaml.cs example code. See http://social.microsoft.com/Forums/is/crm/thread/0831be0c-64e8-4bd3-a473-7317e98271e7 for more info on that one.

      • Larry Q says:

        I feel like a heel, with all these replies. My apologies but I forgot to add something to the post above.

        If you’re having trouble in the AppStart_SQLEntityFramework.cs file with the ‘|DataDirectory|’ value that is set by default in the AppDomain (I did– it pointed to a non-existent directory on my box) and can’t create the SQLCe database the first time through, you can change the value of that parameter in the Start() method of the class, before all the DefaultConnectionFactory stuff. Add this line at the top of the method and you should be good to go:

        AppDomain.CurrentDomain.SetData(“DataDirectory”, “>”);

        I learned about this from the following discussion:
        http://social.msdn.microsoft.com/Forums/en-US/sqlce/thread/dc31ea59-5718-49b6-9f1f-7039da425296/

  5. Raj says:

    This is very big help!

  6. Pingback: Entity Framework Code First 学习资料集合 | 曾冖车记

  7. Pingback: Entity Framework Code-First 学习资料集合 | 曾冖车记

  8. Pingback: Journey of a Windows Phone 7 application (from ideas to deployment) – Introduction « emitsorgroup

  9. Pingback: Entity Framework Code-First, oData & Windows Phone Client | www.nalli.net

  10. @jlafay
    Our next step in the Full Stack (after we make a video covering this material) is to apply these approaches to our full featured application. I’ll let you know .

    Full Stack: http://channel9.msdn.com/Series/The-Full-Stack

  11. Craig says:

    Thanks Jesse,

    The stack gives me the warm fuzzies :)

    Any chance of a follow up of security and validation?

  12. jlafay says:

    Great tutorial on EF, OData, and WP7. I’ve written a few OData services as samples and it seems TOO easy. Is the technology really that simple use in production code? I know that permissions and security needs to be considered when exposing OData. I’m just wondering if there are other powerful features to exploit that may be nestled away in a book or some tutorials somewhere.

  13. Pingback: Tweets that mention Entity Framework Code-First, oData & Windows Phone Client | Jesse Liberty -- Topsy.com

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>