OData (Open Data Protocol) is a web protocol for querying and updating data build upon web technologies such as HTTP, AtomPub and JSON. OData can be used to expose and access data from a several types of data source like databases, file systems and websites.
In this post I will show how to expose data from an existing data source and access the data in a Silverlight application. The data source contains meteorological data about beaches in Copenhagen, Denmark and is hosted in a SQL Azure database.
To be able to expose some data I need to get the data from somewhere. I have created a WCF Service Application called “ODataDemo.Services”. In this project I have created a folder called “Models” and added an EF4 model called “BeachDB.edmx”. The model contains one table called “Beaches” and the Entity Container is called “Entities”. So far it’s all standard EF4.
In Visual Studio 2010 we have an item type called “WCF Data Service” that we can use to expose an OData feed with. I have added a new WCF Data Service called “BeachService.svc”. The service inherits from DataService being the main entry point for developing an ADO.NET Data Service. The DataService requires a type that defines the data service. In this case it’s the Entity Container named “Entities” that I specified in the EF4 model.
By default nobody can read the data I’m exposing through the service. I have to specify the access rules explicitly. If I browse to the service I will just get the title of the service.
In the method “InitializeService” I can specify the access rules. In this scenario I want to allow users to read all data.
If I browse to my service again I can see the collection called “beach” is available. If I browse to the collection (“/beach”) I will get a complete list of all beaches available in the data store (about 30 beaches).
I some cases you want to limit the access the data store. One way to do that is by defining some Query Interceptors. As the name tells we can intercept the queries and modify or limit the result set.
On a beach entity I have a property called “IsMarketPlace”. It indicates if the beach is public available or not. I have added a Query Interceptor called “OnQueryBeach” that will make sure that only the beaches marked with IsMarketPlace = true will be returned.
If I try to browse the list of beaches again I will see that the list is now on down to only two beaches as expected.
Next step is to read the exposed data in a Silverlight browser application. Therefore I have created a new Silverlight Application project called “ODataDemo.Client”.
In Visual Studio 2010 we can access the data from our OData feed by adding a Service Reference that will generate the entities exposed by the feed.
The proxy generated by the Service Reference will also create a DataServiceContext that we can use to run our queries against. In this scenario the DataServiceContext class is called “Entities” taken from the Entity Container.
With the DataServiceContext instantiated, a collection of beaches instantiated and a simple query I’m ready to load some data. When the data is loaded I set the ItemSource of a ListBox that I have added to the start page.
In some scenarios it might not be enough to limit the users’ access to the data using a Query Interceptor and I need a way to identify the users calling my service.
There are several ways to implement authorization. What I will show is a really simplified way to implement authorization and is for demonstration purpose only!
First thing I need to do is to make sure that on every request I get to my service, I need to identify the user calling my service. In the constructor of my service I can subscribe to the ProcessingRequest event. It will fire whenever somebody is requesting the service.
In this case the user will get access if the Authenticate method returns true otherwise the user will get a 401 unauthorized exception. The implementation of Authenticate is really simple and is for demonstration purpose only!
If the header contains “Authorization” with a value of “z7sgeq9n” the user will get access. A real implementation would identify the user and retrieve the users’ roles. In the Query Interceptors I can differentiate the data being returned to the user based on the roles applied to the user.
I need to add the header to my Silverlight application as well. Otherwise I will just get an “Unauthorized exception”. I can add the header information as part of my DataServiceContext object.
With the header information in place I have implemented a simple authorization method to my OData feed.