This will be a longish post .. you have been warned 🙂
I think OData is rather cool .. head over (here) to learn more, if you haven’t already. There is nothing proprietary about it; just culmination of existing technologies of HTTP, AtomPub and Json to provide a platform independent way of sharing information. As I heard someone say “..think of it as RSS for real updateable data..” and in this new age of www as a collection of connected web services rather than collection of web pages, I think OData can play an important role. Why the restrictions against opening up our data to interoperability if we can put adequate security on it?
Now, I wanted to talk about OData from a Windows Phone standpoint (specially WP7.5 or Mango); but also something that applies equally & is just as easily doable on other mobile OS platforms. Most well-designed mobile solutions these days also have a web interface that allows for easier data entry than on a phone form factor; yet data has to stay in sync whenever the user switches between platforms. A centralized data repository with OData feeds seems perfect for a case like this .. so, that’s what we shall talk about in this post.
After looking around a little bit on OData & WP7, I found a lot of examples on how to set up an OData source & consume the feeds from a Windows Phone app. This is obviously the first step & rather important as we shall see; but I also wanted to see if I could set up CRUD operations from WP7 back to the OData source. In the meantime, check out these few posts on how to consume OData in the first place:
- Surely, one of the best ways to play with OData in real world is the Netflix catalog. Netflix worked with MSFT to expose their entire data set through an OData service (here) and now it becomes easy for various applications to consume the vast information in their catalog. This series of posts (here) covers how to build a Windows Phone client to browse through the Netflix catalog.
- Michael Crump did this brilliant series on how to set up an OData source & consume it in Silverlight/Windows Phone. You may find it (here).
- Post (here) from your’s truly on how to consume OData feeds from SQL Azure in a Windows Phone app.
- Heading over to https://www.sqlazurelabs.com/ and logging in to the OData service with admin credentials.
- Then, we select the DB & Table and check the OData checkbox.
- For authentication, we select Anonymous Access so that anybody may access the data without security sign-ons. In real world, this is obviously not good practice. In essence however, Anonymous Access really uses the “dbo” or your admin credentials for SQL Azure operations. So, it should not be too difficult to create users for SQL Azure access & giving them appropriate access rights. This way, the OData service will require submission of security tokens (through ACS or some other federated authentication source) for data access/updates. This post (here) describes the intricacies of the Azure OData service wonderfully. Make sure you copy the OData URL as exposed by your SQL Azure instance.
- Make sure you have the Azure VS SDK (get is from here). This ensures that we can create projects with the Azure wrapper so that our service may be hosted easily in Azure.
- File — New Project — Cloud — Windows Azure Project. This creates the Azure wrapper project. Let’s add an ASP.NET Web Application project to be hosted as Web Role.
- In the ASP.NET project, Add a new item of type ADO.NET Data Entity. This is essentially the ORM mapper that reflects on DB schema and gives us .NET object to play with. In the setup wizard, we make it use an Existing DB & point to the OData Service URL as exposed by our SQL Azure table. You will be required to enter your SQL Azure Admin DB credentials or some other user access details. This should build the proxies out of the OData metadata, and thus expose the service offerings to our project. For our “Team” table in SQL Azure exposed through OData, the data model looks like this:
- Next, we add a WCF Data Service to the project which should expose out the data provided by the ADO.NET data service. The configuration of the SVC.cs file should look something like this:
- Notice how we ask for building a collection of data objects of the same entity type as exposed by our ADO.NET data model. Also, we allow this service to have access rights of “All ” so that we may perform CRUD against the SQL Azure table at will.
- If everything goes well, we should be able to right-click on the .SVC file & do a “View in Browser“. This should get us to the same OData view as in Azure; you should be able to drill in & see all your data through OData filtering on browser URL.
- So, by now we have our own service ready & pointed to the SQL Azure OData service with user credentials configured as needed. Now, this service is ready for primetime hosting in Azure.
- We right click on the solution & choose “Publish” and create the packages locally in our bin directory. This makes two files — a .cspkg application wrapper & a .cscfg configuration file.
- We simply create a new Hosted Service in Azure and push out these files & swap their IP to be Production. The end state looks something like this:
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
namespace WebRole1
{
public class DemoService : DataService
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Teams", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
using Demo;
using System.Data.Services.Client;
namespace SQLAzureOData_Demo
{
using DemoService;
public partial class MainPage : PhoneApplicationPage
{
private static DemoEntities wcfContext = null;
private void InsertDataThruService()
{
wcfContext = new DemoEntities(new Uri("http://YourAzureServiceNDS.cloudapp.net/DemoService.svc/"));
var TeamMember = Team.CreateTeam(3);
TeamMember.Name = "Mike";
TeamMember.TwitterHandle = "@michaelcollier";
var collection = new DataServiceCollection(wcfContext);
collection.Add(TeamMember);
wcfContext.BeginSaveChanges(new AsyncCallback(SaveChangesCB), null);
}
private void SaveChangesCB(IAsyncResult asynchronousResult)
{
// Warning: You are on a different thread!
// Success or Error Handling.
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("All done!");
LoadTeam();
});
}
}
}
Just a few points to mention. On hitting the “+” App icon, I have a little UI pop-up that accepts the new Team members Name & TwitterHandle. The code sample above hard-codes the user; but you get the point that the UI needs to fire the “InsertDataThruService” method. Once we have the “WCFContext”, you can see how easy it gets to manipulate the data through any CRUD operations. Another important point to keep in mind is that the “BeginSaveChanges” call is asynchronous, this being Silverlight. So, the “SaveChangesCB” callback delegate does not fire on the same UI thread. This is important to keep in mind if you start wondering why the message pop-up or the refresh of the Team member list in our case, does not fire.
That’s it, few steps; but now we have a fully functional data repository that exposes OData feeds and can be read/updated from multiple platforms. This Service Reference way is just one way to do CRUD on an OData service though. In the next post, we talk about how to do this natively.
Hope this was helpful.
Adios!
I have a very similar setup, but when i try to update the odata service, i get a simple “NotFound” response. I’m not adding but simply changing a record.
Any ideas
Merasheen,
Sorry to be late in replying. Little more context will help. How did you set up your OData service? Is the entity in question set up to allow edits? How are you constructing your update logic? Please feel free to email if you want to take this off-line.
Thanks!
great post thank you very much!
one question though, i’ve created a “windows phone cloud application” project from the template of windows phone toolkit for windows azure. there, in the web project i can see a directory called services which have all the DataService classes.
i dont see any .svc files, only .cs but nevertheless the phone can communicate with the asp.net mvc3 server application. is it using a different method than the one you described ? the DataService class is defined as:
public class SqlAzureSampleODataService : DataService and it is consumed on the WP client side, but no svc file…
Michael,
Yes .. you are right. No WCF endpoint as such. The Web project created by the template is an MVC app, with Controller acting as endpoints through routing. Take a look at the App.xaml resources in the WP app for endpoints and then the PushNotificationsController.cs in the web app.
Hope this helps! Glad to see you trying things out & poking inside the workings of the toolkit.
Thanks!
thanks a lot for the direction !
Do you know where i can i read about this method or maybe a tutorial that is using the same pattern ? because most of the stuff i read are about using WCF and consuming the services.
Thanks again for the answer.
miked,
It depends on what you are trying to accomplish through your service/MVC action. Try this: http://stackoverflow.com/questions/3499514/wcf-rest-service-or-asp-net-mvc-controllers-actions. You could also read up on MVC tutorials that’ll show how to have MVC ActionResults serve up JSon/XML. The important distinction is that it is not a standalone web service like WCF.
Thanks!