The purpose of this article is to show you how to open the application demonstrated in the previous article via an OData endpoint. We will then discover the limitations of this endpoint in the current release of WCF RIA Services and its differences with the features offered by the WCF Data Services framework. At last, we will see how to consume this endpoint from the Office Excel application and from a web application written with WebMatrix.
This article is the second one out of 5:
1 – Review of the initial application
2 – How to expose the service as an OData stream consumed by Excel and from a web application built with WebMatrix (this article)
3 – How to expose the service as a “standard” WCF Service used from a WPF application and a Windows Phone 7 application
4 – How to expose the service as a JSON stream to be used by a HTML5/jQuery web application
5 – Step by step procedure to publish this WCF RIA Services application to Windows Azure & SQL Azure
Introduction to OData
First of all, we need to have a basic knowledge of what OData is. If you don’t know anything about this protocol/technology yet, here are some articles and webcast I’m suggesting you to read/watch:
1 – The official website OData.org
2 – WCF Data Services and OData At-a-Glance
3 – The MIX10 session : OData: There's a Feed for That
4 – Beginner's Guide to WCF Data Services
Lastly, we’ve then seen some increasing usage of OData inside our Microsoft products. Developers can easily expose their data by using the .NET 4.0 WCF Data Services framework for instance. This framework will then consume a LINQ source, it will analyze it and it will expose it via HTTP REST. You will then have a CRUD support of your entities. You will have also a LINQ provider on the client side (Silverlight, WPF) to remotely query your data source.
On the producers’ side, SharePoint 2010 can expose its lists through OData. SQL Azure can expose its databases directly through an OData feed by simply enabling a checkbox (currently only available through the beta program of SQL Labs). At last, Windows Azure exposes its data tables via OData also.
Enabling the OData endpoint on a WCF RIA Services DomainService
There is 2 ways to add an OData endpoint to your RIA Services. During the assisted generation, one of the wizard options offers you to add it via a simple checkbox “Expose OData endpoint”:
And you’re done. If you have an existing solution, you can also add the OData endpoint after the wizard process. For that, the first thing to do is to declare it inside your web.config file with the following piece of XML:
<add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
Just after the following tag:
After that, you need to specify in your DomainService’s code which method will be called by default on the URL /NameOfYourEntity thanks to the following attribute:
[Query(IsDefault = true)]
For instance, if you’re taking the source code of the Book Club application shared in the previous article, you need to review these 2 following methods:
[Query(IsDefault = true)]
public IQueryable<Book> GetBooks()
return this.ObjectContext.Books.OrderBy(b => b.Title);
[Query(IsDefault = true)]
public IQueryable<Category> GetCategories()
return this.ObjectContext.Categories.OrderBy(c => c.CategoryName);
Once done, the endpoint will be available through this kind of formatted URL:
This formatting works if you’ve generated your solution by creating it with the “Silverlight Business Application” template. If you added your DomainService manually to your ASP.NET project, this will probably more look like this:
For instance, with our Book Club application, after adding the OData endpoint, here is the URL to use:
Because our DomainService is being hosted inside the BookShelf.Web project inside the Services directory. With my current hosting in Azure, you can then freely play with this public URL:
Thus, if you’re using the Silverlight OData Explorer application with this public URL in Azure, you’ll have this kind of output:
Note: you’ll need to install & run the Silverlight OData Explorer application in the elevated trust “Out of Browser” mode to by-pass the native cross-domains calls limitations of Silverlight as I haven’t set a cross domain policy file on the root of my hosting.
Limitations of the WCF RIA Services OData endpoint and differences with WCF Data Services
Well, OData seems to be wonderful! If I’m exposing my WCF RIA Services layer with OData, am I the king of the world? Well, not yet…
The OData version exposed by WCF Data Services is indeed very powerful and can be used perfectly in open & interoperable scenarios. However, the OData endpoint of WCF RIA Services is unfortunately today less powerful. For instance, if you need to remotely control the WCF RIA Services layer in a complete way from a WPF, Objective-C or even an Android client like a customer recently asked me, I would rather suggesting you to use the SOAP endpoint (more or less like a classic WebService then) or to use the JSON endpoint like we will see in the next 2 following articles.
So why is it less powerful? Simply because the OData endpoint only supports read-only access to the entities exposed by RIA Services and it doesn’t support query operations neither. This is something we will maybe change in the next version of RIA Services but in the meantime you will have to deal with those limitations of this v1.0.
Still, if those limitations aren’t a problem for you, that’s perfect! You will then be able to cover these needs:
1 – The main need in your project is to build a Web RIA application and you’ll then need to have the maximum productivity on this point
2 – You need to expose the same data in read-only mode to other type of clients without having the need to remotely drive the server data source to add filtering or sorting logic
The main need will be cover by the very high SL4 – WCF RIA Services – ASP.NET 4.0 productivity chain. The second need will be cover by the OData endpoint. You will then be able to connect mobile devices like Windows Phone 7, Android or iPhone iOS on your services without problems.
Review of the OData support of WCF Data Services
In order to better understand the RIA Services OData limitations, let’s first review the native features offered by WCF Data Services. For that, we will use the famous NorthWind SQL Server sample publicly available via this OData feed: http://services.odata.org/Northwind/Northwind.svc/
We can consume this database with the following queries (you can test these URLs inside your browser to see the output or inside a tool like the Silverlight OData Explorer):
http://services.odata.org/Northwind/Northwind.svc/Customers/ to return the list of all customers available in the database
http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/ to return a specific customer based on its Id (‘ALKFI’ here)
http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/Orders to return the list of all linked orders to the ‘ALKFI’ customer.
http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/Orders?$filter=OrderID gt 10700 to query among all the orders done by the ‘ALKFI’ customer and to return only the orders having an OrderID greater than 10700.
By the way, if you have a .NET client (Silverlight or WPF) connecting to this OData feed, you will be able to enjoy the power of the LINQ provider and the WCF proxy on the client side. For instance, the previous HTTP request/query could be rather translated into this nice LINQ query:
var ordersQuery = from o in context.Orders
where o.Customers.CustomerID == "ALFKI" && o.OrderID > 10700
An expression tree will then be built in memory, will be analyzed and transformed into the appropriate HTTP request when we’ll need it.
As a reminder also, don’t forget that you can add, update or delete items on the OData feed available with WCF Data Services.
Review of the OData support of WCF RIA Services
On the WCF RIA Services side, let’s review the kind of requests we can do:
http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-Services-BookClubService.svc/OData/BookSet to return the list of all books available in my SQL Azure database… and… that’s all!
Indeed, if you tries more complex requests for instance by selecting a specific item:
or by trying to set a filter:
http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-Services-BookClubService.svc/OData/BookSet?$filter=BookID gt 39
You will respectively receive the 2 following exceptions: “Requests that attempt to access a single element using key values from a result set are not supported.” and “Query options are not allowed.”. Well, you won’t say for this time that our error messages aren’t clear enough.
Note : if you need further explanations on the alignment between both framework, you can read this article : WCF, Data Services and RIA Services Alignment Questions and Answers
Otherwise, you can still use both!
Another option is to simply to use both frameworks. What would be the benefits? Again, let’s talk about a specific scenario I’ve seen with one of my customers:
1 – You need to create a Web RIA application based on Silverlight and you need to have the optimum productivity on this application. This will be for instance the main back office application used internally by your company.
2 – You need to expose the same data on the public internet with support of read/write operations as well as queries operations for other types of clients like the iPad/iPhone/Windows Phone 7/Android devices.
For the first point, this is still the Silverlight 4 & WCF RIA Services couple that will help you the most. You will then benefit from the tiedly .NET 4.0/Silverlight 4 couple for a high productivity chain offering a lot of the logic for you on the client side: high level controls, client-side validation, etc.
For the second point, if you’re enabling the SOAP endpoint on your RIA Services DomainServices (like we’ll see together on the next article), you will offer read/write operations on your entities for the mobile devices specified above. However, you won’t have the native support of query operations like we just see in the full OData support of WCF Data Services. We could then imagine injecting the data model used by your RIA Services layer into WCF Data Services.
Indeed, if you’re using an Entity Framework model like we’re currently using in the Visual Studio 2010 solution shared in the previous article, the WCF Data Services support will be added in a few mouse clicks. For that, add a new “WCF Data Service” element inside the “Services” directory and named it “BooksDataService”:
Ask to the WCF Data Services framework to analyze the BookShelf.Web.Models.BookClubEntities model. This is the same model currently used by our RIA Services layer. You then have to choose which entity you’d like to expose with which level of rights (read, write, etc.). For instance, this piece of code is exposing all entities available in our model using the full level of rights (read/write):
public class BooksDataService : DataService<BookShelf.Web.Models.BookClubEntities>
public static void InitializeService(DataServiceConfiguration config)
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
You will then have a new URL available exposing this time a full OData feed (read, write, queries, filtering, etc.). In my case, here is the Azure URL:
Thus, we will be able to execute more complex search operations. If we’re taking as a base the sample demonstrated in the previous article, we were querying the books members of the “Technology” category which the author contains the keyword “Papa”. We can then now build the following corresponding HTTP request with our full OData feed:
http://bookclub.cloudapp.net/Services/BooksDataService.svc/Categories(1)/Books?$filter=substringof('Papa', Author) eq true
Updating or deleting entities will be possible also thanks to the level of rights you will set with the SetEntitySetAccessRule() method. If you’re looking for more query operators, you can have a look here: http://www.odata.org/developers/protocols/uri-conventions#QueryStringOptions
Drawbacks: of course, there is some inconvenient to use the 2 frameworks in the same time in your project. First of all, this implies a double maintenance of the code as you’re rewriting some of the same logic in 2 different areas. Moreover, you have to handle the security access on the 2 frameworks also. Indeed, if you’re allowing updates only for a specific set of users using the security attributes of WCF RIA Services, you will have to reflect these security constraints on the WCF Data Services layer also. You will then see in the next article the benefits of using a unique framework (RIA Services) to expose our data on which we’re setting the appropriate set of rights.
Consuming the OData endpoint of RIA Services from Excel
After this relatively long – but important – introduction, let’s now see how to consume our RIA Services layer from Excel.
Note: we will use here the native features of RIA Services and its limited OData endpoint. We won’t use here the full OData logic offered by WCF Data Services.
The first thing to do is to download the PowerPivot Add-in for Excel 2010: http://www.powerpivot.com/download.aspx
Once you’ve installed the add-in, you’ll notice a new section named PowerPivot in the Excel ribbon. Click on the “PowerPivot window” button:
Then click on the “import from a data feeds” button:
Enter the URL pointing on the books returned by my OData endpoint hosted in Azure: http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-Services-BookClubService.svc/OData/BookSet :
You should have this kind of window indicating that the import process worked as expected:
You can now manipulate the data in Excel to do sorting operations, generating some charting, etc.:
At this stage, we can already load a consequent amount of data inside the Excel client that will load all the entities in memory for further operations.
Consuming the OData endpoint of RIA Services from an application written with WebMatrix
If you don’t know WebMatrix yet, you can discover this new free tool that helps you to simply build web applications via this set of nice tutorials & walkthroughs: http://www.asp.net/webmatrix/tutorials . If you’re an ASP developer who hasn’t moved to ASP.NET yet or if you’re a PHP developer curious to see what’s going on in the Microsoft space, this tool should interest you.
Ok, let’s go. Let’s discover that thanks to the powerful helpers shipped for WebMatrix (that you can re-use in ASP.NET MVC 3 applications by the way) and thanks to the new Razor syntax, we’re going to build a nice little web application in a couple of steps to display our books stored in SQL Azure and available via our OData endpoint.
Note: if you’re an ASP.NET developer and you don’t know the Razor syntax yet, you have to read Scott Guthrie’s posts on this topic! The introduction post is here: Introducing “Razor” – a new view engine for ASP.NET
1 – Run WebMatrix, create a new site from the “Starter Site” template and named it “WebMatrixBookClub”:
Change the master page “_SiteLayout.cshtml” to find & replace the string “My ASP.NET Web Page” referenced 3 times by “WebMatrix BookClub Application”.
Then change the “Default.cshtml” page by this content:
Layout = "~/_SiteLayout.cshtml";
Page.Title = "List of available books";
Display here the list of books from the OData endpoint
You can already start testing the result by pressing on the “Run” button or the “F12” key:
You’ll obtain this ultra-simple page:
2 – To get access to the data from the OData endpoint, we need a specific helper which is not installed by default with WebMatrix. Fortunately, it’s available online and it’s very simple to install. Navigate to the same URL by just adding “/_Admin”:
Create a new password as requested and display the packages available online to download & install the OData helper:
If everything goes ok, you will have this success message:
3 – Now, we can start coding the logic that will get the data and format it in our HTML page. For that, open the “Default.cshtml” page and replace its content by this one:
Layout = "~/_SiteLayout.cshtml";
Page.Title = "List of available books";
var result = OData.Get("http://bookclub.cloudapp.net/ClientBin/BookShelf-Web-Services-BookClubService.svc/OData/BookSet");
var grid = new WebGrid(source: result,
We’re using here the OData helper to send the request to our WCF RIA Services endpoint thanks to the OData.Get() method. After that, we’re providing the result to another helper named WebGrid. We ask it to sort the data by “Author” and to display it on pages with 10 elements maximum.
At last, rather than displaying all the columns, we’re asking to the helper to only display the “Author”, “Title” & “ASIN” columns via the GetHtml() method .
If you now re-launch the application, you’ll have this nice output:
Very easy to code, isn’t it? In only 3 steps, we’re getting the data from the OData endpoint and we’re formatting them in a nice high level WebGrid control!
If you’re curious about the other features available inside the WebPages technology used by the WebMatrix tool, you can navigate here: http://www.asp.net/webmatrix/tutorials/asp-net-web-pages-api-reference . You’ll find other kinds of very interesting helpers to display a Twitter feed, to let your users say they like this page in FaceBook, etc. You can even re-use this new productivity approach and this new Razor syntax into bigger projects based on ASP.NET MVC 3.
That concludes this OData article. See you in the next article where we’ll see how to expose the same service via a SOAP endpoint to enable a full access to WPF and/or Windows Phone 7 applications.