Reference Data Caching Walkthrough

This walkthrough shows how a simple web application can be built using the reference data caching features in the “Microsoft WCF Data Services For .NET March 2011 Community Technical Preview with Reference Data Caching Extensions” aka “Reference Data Caching CTP”. The walkthrough isn’t intended for production use but should be of value in learning about the caching protocol additions to OData as well as to provide practical knowledge in how to build applications using the new protocol features.

Walkthrough Sections

The walkthrough contains five sections as follows:

  1. Setup: This defines the pre-requisites for the walkthrough and links to the setup of the Reference Data Caching CTP.
  2. Create the Web Application: A web application will be used to host an OData reference data caching-enabled service and HTML 5 application. In this section you will create the web app and configure it.
  3. Build an Entity Framework Code First Model: An EF Code First model will be used to define the data model for the reference data caching-enabled application.
  4. Build the service: A reference data caching-enabled OData service will be built on top of the Code First model to enable access to the data over HTTP.
  5. Build the front end: A simple HTML5 front end that uses the datajs reference data caching capabilities will be built to show how OData reference data caching can be used.

 

Setup

The pre-requisites and setup requirements for the walkthrough are:

  1. This walkthrough assumes you have Visual Studio 2010, SQL Server Express, and SQL Server Management Studio 2008 R2 installed.
  2. Install the Reference Data Caching CTP. This setup creates a folder at “C:\Program Files\WCF Data Services March 2011 CTP with Reference Data Caching\Binaries\” that contains:
    • A .NETFramework folder with:
      • i. An EntityFramework.dll that allows creating off-line enabled models using the Code First workflow.
      • ii. A System.Data.Services.Delta.dll and System.Data.Services.Delta.Client.dll that allow creation of delta enabled Data Services.
    • A JavaScript folder with:
      • i. Two delta-enabled datajs OData library files: datajs-0.0.2 and datajs-0.0.2.min.js.
      • ii. A .js file that leverages the caching capabilities inside of datajs for the walkthrough: TweetCaching.js

 

Create the web application

Next you’ll create an ASP.NET Web Application where the OData service and HTML5 front end will be hosted.

  1. Open Visual Studio 2010 and create a new ASP.NET web application and name it ConferenceReferenceDataTest.  When you create the application, make sure you target .NET Framework 4.
  2. Add the .js files in “C:\Program Files\WCF Data Services March 2011 CTP with Reference Data Caching\Binaries\Javascript” to your scripts folder.
  3. Add a reference to the new reference data caching-enabled data service libraries found in “C:\Program Files\WCF Data Services March 2011 CTP with Reference Data Caching\Binaries\.NETFramework”:
    • Microsoft.Data.Services.Delta.dll
    • Microsoft.Data.Services.Delta.Client.dll
  4. Add a reference to the reference data caching-enabled EntityFramework.dll found in in “C:\Program Files\WCF Data Services March 2011 CTP with Reference Data Caching\Binaries\.NETFramework”.
  5. Add a reference to System.ComponentModel.DataAnnotations.

Build your Code First model and off-line enable it.

In order to build a Data Service we need a data model and data to expose.  You will use Entity Framework Code First classes to define the delta enabled model and a Code First database initializer to ensure there is seed data in the database. When the application runs, EF Code First will create a database with appropriate structures and seed data for your delta-enabled service.

  1. Add a C# class file to the root of your project and name it model.cs.
  2. Add the Session and Tweets classes to your model.cs file. Mark the Tweets class with the DeltaEnabled attribute. Marking the Tweets class with the attribute will force Code First to generate additional database structures to support change tracking for Tweet records.

public class Session
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime When { get; set; }
    public ICollection<Tweet> Tweets { get; set; }
}

[DeltaEnabled]
public class Tweet
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column(Order = 1)]
    public int Id { get; set; }

    [Key]
    [Column(Order = 2)]
    public int SessionId { get; set; }

    public string Text { get; set; }

    [ForeignKey("SessionId")]
    public Session Session { get; set; }
}

Note the attributes used to further configure the Tweet class for a composite primary key and foreign key relationship. These attributes will directly affect how Code First creates your database.

3.   Add a using statement at the top of the file so the DeltaEnabled annotation will resolve:

 using System.ComponentModel.DataAnnotations;

4. Add a ConferenceContext DbContext class to your model.cs file and expose Session and Tweet DbSets from it.

 public class ConferenceContext : DbContext  {      public DbSet<Session> Sessions { get; set; }      public DbSet<Tweet> Tweets { get; set; }  }

5. Add a using statement at the top of the file so the DbContext and DbSet classes will resolve:

 using System.Data.Entity;

6. Add seed data for sessions and tweets to the model by adding a Code First database initializer class to the model.cs file:

 public class ConferenceInitializer : IncludeDeltaEnabledExtensions<ConferenceContext>  {      protected override void Seed(ConferenceContext context)      {          Session s1 = new Session() { Name = "OData Futures", When = DateTime.Now.AddDays(1) };          Session s2 = new Session() { Name = "Building practical OData applications", When = DateTime.Now.AddDays(2) };            Tweet t1 = new Tweet() { Session = s1, Text = "Wow, great session!" };          Tweet t2 = new Tweet() { Session = s2, Text = "Caching capabilities in OData and HTML5!" };            context.Sessions.Add(s1);          context.Sessions.Add(s2);          context.Tweets.Add(t1);          context.Tweets.Add(t2);          context.SaveChanges();      }  }

7. Ensure the ConferenceIntializer is called whenever the Code First DbContext is used by opening the global.asax.cs file in your project and adding the following code:

 void Application_Start(object sender, EventArgs e)  {              // Code that runs on application startup              Database.SetInitializer(new ConferenceInitializer());    }

Calling the initializer will direct Code First to create your database and call the ‘Seed’ method above placing data in the database

8. Add a using statement at the top of the global.asax.cs file so the Database class will resolve:

 using System.Data.Entity;

Build an OData service on top of the model

Next you will build the delta enabled OData service. The service allows querying for data over HTTP just as any other OData service but in addition provides a “delta link” for queries over delta-enabled entities. The delta link provides a way to obtain changes made to sets of data from a given point in time. Using this functionality an application can store data locally and incrementally update it, offering improved performance, cross-session persistence, etc.

1. Add a new WCF Data Service to the Project and name it ConferenceService.

AddNewgif

2. Remove the references to System.Data.Services and System.Data.Services.Client under the References treeview. We are using the Data Service libraries that are delta enabled instead.

3. Change the service to expose sessions and tweets from the ConferenceContext and change the protocol version to V3. This tells the OData delta enabled service to expose Sessions and Tweets from the ConferenceContext Code First model created previously.

 public class ConferenceService : DataService<ConferenceContext>  {      // This method is called only once to initialize service-wide policies.      public static void InitializeService(DataServiceConfiguration config)      {          config.SetEntitySetAccessRule("Sessions", EntitySetRights.All);          config.SetEntitySetAccessRule("Tweets", EntitySetRights.All);          config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;      }  }

4. Right-click on ConferenceService.svc in Solution Explorer and click “View Markup”. Change the Data Services reference as follows.

Change:

<%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Service="ConferenceReferenceDataTest.ConferenceContext" %>

To:

<%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, Microsoft.Data.Services.Delta, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Service="ConferenceReferenceDataTest.ConferenceService" %>

6. Change the ConferenceService.svc to be the startup file for the application by right clicking on ConferenceService.svc in Solution Explorer and choosing “Set as Start Page”.

7. Run the application by pressing F5.

  • In your browser settings ensure feed reading view is turned off. Using Internet Explorer 9 you can turn feed reading view off by choosing Options->Content then clicking “Settings for Feeds and Web Slices”. In the dialog that opens uncheck the “Turn on feed reading view” checkbox.

clip_image003

<link rel="https://odata.org/delta" href=https://localhost:11497/ConferenceService.svc/Tweets?$deltatoken=2002 />

The delta link is shown because the DeltaEnabled attribute was used on the Tweet class.

  • The delta link will allow you to obtain any changes made to the data based from that current point in time. You can think of it like a reference to what your data looked like at a specific point in time. For now copy just the delta link to the clipboard with Control-C.

8. Open a new browser instance, paste the delta link into the nav bar: https://localhost:11497/ConferenceService.svc/Tweets?$deltatoken=2002, and press enter.

9. Note the delta link returns no new data. This is because no changes have been made to the data in the database since we queried the service and obtained the delta link. If any changes are made to the data (Inserts, Updates or Deletes) changes would be shown when you open the delta link.

10. Open SQL Server Management Studio, create a new query file and change the connection to the ConferenceReferenceDataTest.ConferenceContext database. Note the database was created by a code first convention based the classes in model.cs.

11. Execute the following query to add a new row to the Tweets table:

insert into Tweets (Text, SessionId) values ('test tweet', 1)

12. Refresh the delta link and note that the newly inserted test tweet record is shown. Notice also that an updated delta link is provided, giving a way to track any changes from the current point in time. This shows how the delta link can be used to obtain changed data. A client can hence use the OData protocol to query for delta-enabled entities, store them locally, and update them as desired.

13. Stop debugging the project and return to Visual Studio.

Write a simple HTML5 front end

We’re going to use HTML5 and the reference data caching-enabled datajs library to build a simple front end that allows browsing sessions and viewing session detail with tweets. We’ll leverage a pre-written library that uses the reference data capabilities added to OData and leverages the datajs local store capabilities for local storage.

1. Add a new HTML page to the root of the project and name it SessionBrowsing.htm.

2. Add the following HTML to the <body> section of the .htm file:

 <body>  <button id='ClearDataJsStore'>Clear Local Store</button>  <button id='UpdateDataJsStore'>Update Tweet Store</button>  <br />  <br />  Choose a Session:   <select id='sessionComboBox'>  </select>  <br />  <br />  <div id='SessionDetail'>No session selected.</div>  </body>  

3. At the top of the head section, add the following script references immediately after the head element:

 <head>       <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.2.min.js" type="text/javascript"></script>      <script src=".\Scripts\datajs-0.0.2.js" type="text/javascript"></script>      <script src=".\Scripts\TweetCaching.js" type="text/javascript"></script>  …

4. In the head section, add the following javascript functions. These functions:

  • Pull sessions from our OData service and add them to your combobox.
  • Create a javascript handler for when a session is selected from the combobox.
  • Create handlers for clearing and updating the local store.
     <script type="text/javascript">          //load all sessions through OData          $(function () {              //query for loading sessions from OData              var sessionQuery = " ConferenceService.svc/Sessions?$select=Id,Name";              //initial load of sessions              OData.read(sessionQuery,                      function (data, request) {                          $("#sessionComboBox").html("");                          $("<option value='-1'></option>").appendTo("#sessionComboBox");                          var i, length;                          for (i = 0, length = data.results.length; i < length; i++) {                              $("<option value='" + data.results[i].Id + "'>" + data.results[i].Name                                   + "</option>").appendTo("#sessionComboBox");                          }                      },                      function (err) {                          alert("Error occurred " + err.message);                      }                  );                //handler for combo box              $("#sessionComboBox").change(function () {                  var sessionId = $("#sessionComboBox").val();                  if (sessionId > 0) {                        var sessionName = $("#sessionComboBox option:selected").text();                      //change localStore to localStore everywhere and TweetStore to be TweetStore                      var localStore = datajs.createStore("TweetStore");                        document.getElementById("SessionDetail").innerHTML = "";                      $('#SessionDetail').append('Tweets for session ' + sessionName + ":<br>");                      AppendTweetsForSessionToForm(sessionId, localStore, "SessionDetail");                    } else {                      var detailHtml = "No session selected.";                      document.getElementById("SessionDetail").innerHTML = detailHtml;                  }              });                //handler for clearing the store              $("#ClearDataJsStore").click(function () {                  ClearStore();              });                //handler for updating the store              $("#UpdateDataJsStore").click(function () {                  UpdateStoredTweetData();                  alert("Local Store Updated!");              });            });          </script>    

5. Change the startup page for the application to the SessionBrowsing.htm file by right clicking on SessionBrowsing.htm in Solution Explorer and choosing “Set as Start Page”.

6. Run the application. The application should look similar to:

clip_image005

  • Click the ‘Clear Local Store’ button: This removes all data from the cache.
  • Click the ‘Update Tweet Store’ button. This refreshes the cache.
  • Choose a session from the combo box and note the tweets shown for the session.
  • Switch to SSMS and add, update or remove tweets from the Tweets table.
  • Click the ‘Update Tweet Store’ button then choose a session from the drop down box again.  Note tweets were updated for the session in question.

This simple application uses OData delta enabled functionality in an HTML5 web application using datajs. In this case datajs local storage capabilities are used to store Tweet data and datajs OData query capabilities are used to update the Tweet data.

Conclusion

This walkthrough offers an introduction to how a delta enabled service and application could be built. The objective was to build a simple application in order to walk through the reference data caching features in the OData Reference Data Caching CTP. The walkthrough isn’t intended for production use but hopefully is of value in learning about the protocol additions to OData as well as in providing practical knowledge in how to build applications using the new protocol features. Hopefully you found the walkthrough useful. Please feel free to give feedback in the comments for this blog post as well as in our prerelease forums here.

Comments

  • Anonymous
    April 13, 2011
    I like delta-enabled! Just about makes up for OData not supporting timestamp columns.

  • Anonymous
    April 14, 2011
    Will this play well with Azure AppFabric Caching and multiple WebRoles?

  • Anonymous
    May 18, 2011
    This is amazing! Now please put it in CRM2011 and SharePoint2011 XD