June10

Exposing OData from an Entity Framework Model

VistaDB exposing oData through WCF Data ServiceAfter reading Scott Hansleman’s article on exposing OData for Stack Overflow I thought it would be nice to update the previous post I did on Ado.net data services to include the new WCF Data Services.  WCF Data Services (formerly called Ado.net Data Services, and “Astoria”) can expose OData to callers through a very simple interface. LINQPad was not available to query the interface at the time, so I will also discuss how to use LINQPad to write queries against a Data Service.

For my example I am going to expose a VistaDB test database that shows SQL Commands, and examples of their syntax.  It is a very simple model, but provides interesting data to query against (other than Northwind!).  You can use any Entity Framework provider to perform these steps, they are not specific to VistaDB.

Being able to consume data across the web in a rest-ful manner is part of the power of OData, lots of applications that are powered by .Net are going to be able to consume OData services very easily.  But the OData protocol is not just for .Net, PHP, Java, Javascript and others also have the ability to consume the data.

What is OData?

The Open Data Protocol (OData) is an open web protocol started by Microsoft to expose data using existing web technologies.  HTTP, AtomPub (similar to RSS), and JSON are all supported.  The protocol matches very closely the way web technologies work, and the URL is the primary operator on the data query.  The HTTP verbs match very closely their CRUD operations.  The URL has a very descriptive syntax that makes it easy to build queries by hand, or with any programming language.  OData is not unique to .Net, although .Net sure makes it easy to expose and consume OData through WCF.

WCF Data Service

To expose OData we will build a WCF Data Service and expose our VistaDB EF model.  I am using Visual Studio 2010 and .Net 4 for this example.  The WCF Data Service item template in Visual Studio makes it very easy to expose an Entity Framework model over a service based interface.  You don’t have to use Entity Framework, but doing so makes it really easy to build and deploy.  I believe you could expose a custom collection through the data service as well, but I have not tried this yet.

Creating the Entity Framework Model

2010-06-07_1547-Command-EF-ModelI first created a Visual Studio 2010 Web Application targeted to .Net 4.   Then through right clicking on the project Add - New Item and then choose the Ado.Net Entity Data Model.

This is a simple model against a VistaDB 4 database named CommandToolDB.vdb4.  We have been using this internally to build up samples of SQL code for VistaDB and SQL Server, then flagging the differences in the database.  This is not a completed project, so I am only including a sample of the dataset with this service. 

We would like to eventually have this service exposed online and queryable through Data Builder.  That would allow people to look up snippet examples of SQL Syntax and see the differences between VistaDB and SQL Server. 

Creating an OData / WCF Data Service

Right click on the project, Add – New Item – WCF Data Service.  I named the service VistaDBCommandService.svc.  To add any class to be exposed through OData all you have to do is change the class name in the DataService< ClassNameHere > definition.  The default class generated by the template includes a comment in the class definition where you put your class name.

public class VistaDBCommandService : DataService< VistaDBCommandsEntities >

Since we are exposing the EF Model, I put the name of the entities class as the type to be exposed.

public static void InitializeService(DataServiceConfiguration config)
{
    // Give readonly access to all of the entities
    config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
    
    // Pagesize will change the max number of rows returned
    config.SetEntitySetPageSize("*", 25);

    config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}

View the Feed Output

Right click the service and choose View in Browser. You will see the following output (well, it will look like an RSS Feed if your browser knows how – so you may need to view source to see this ).   The PORT number will be different on your machine.  Visual Studio changes the localhost port, so pay attention to the URL shown when you run the service.  If you never run the service the asp.net webserver will not have started and you will get an error.

<service xml:base="http://localhost:1883/VistaDBCommandService.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="Commands"> 
      <atom:title>Commands</atom:title> 
    </collection> 
    <collection href="Databases"> 
      <atom:title>Databases</atom:title> 
    </collection> 
    <collection href="Statuses"> 
      <atom:title>Statuses</atom:title> 
    </collection> 
  </workspace> 
</service>

The links are all relative, and can be used to query the entities in the database.  Pick one of those links to see the details below.  In my model there is a Commands table, so the commands entry below will be valid.  If you are using a different model, pick on of your entity names.

OData Feed View Commands EntityBrowse to the Commands Entity

Pointing by browser to the commands entity ends up looking something like this in my browser.

http://localhost:1883/VistaDBCommandService.svc/Commands

Not very pretty is it?

But now you can write some queries against the data just from the URL parameters.

http://localhost:1883/VistaDBCommandService.svc/Commands()?$top=5&$select=SQLCommand,ExampleSyntax

That will give me the First 5 commands (top=5) and only return the SQLCommand, and ExampleSyntax instead of the entire object.

Ok, but who wants to write queries in the browser?  We want LINQ!

LINQPad 4 Beta and OData

2010-06-07_1609 Grab the most recent LINQPad 4 beta for .Net 4 and follow along.

In LINQPad click the Add Connection at the top of the left panel.  The dialog will appear that allows you to choose what type of connection you want, and if you want an automatic data context built for you.

Choose the WCF Data Services option from that dialog and click Next.  The LINQPad connection dialog then appears.  Choose the Data Services radio button, and then enter the local service.  In my case it was the URL listed in the box.  I found this by looking the browser window launched when I clicked view in browser for the service item of the website.  Clicking test should bring up the Connection OK dialog.

Data Service in LINQPad

LINQPAD DataService ViewNow our data service is in LINQPad and looks like the image show here.  The entities are exposed, and so are their relationships.

We can now write LINQ queries against our data service and see the results in a nice graphical way inside of LINQPad.

LINQPad knows how to query the WCF Data Service and dynamically built up a local model for querying against.  The SQL output from LINQPad will now show the URL it used to query the service.

This is very similar to how Silverlight loads data exposed on remote servers without knowing anything about ADO.Net.

LINQ Query Against the Data Service

(from c in Commands
where c.Status.Description.Equals("Implemented") &&
    c.Database.Description.Equals("VistaDB")
select new { c.SQLCommand, c.ExampleSyntax }).Take( 5 )

This command queries the database to find those entries that are flagged as implemented, for the VistaDB Database, and gets the first five entries SQLCommand and ExampleSyntax columns.

Notice how I was able to drill down into the entities (c.Status.Description) and interact with the data very much like I would a local EF model.

The results look like this in the Results pane.

2010-06-07_1618

Viewing the SQL in LINQPad shows the following URL:

http://localhost:1883/VistaDBCommandService.svc/Commands()?$filter=(Status/Description eq 'Implemented') and (Database/Description eq 'VistaDB')&$top=5&$select=SQLCommand,ExampleSyntax

The entire LINQ statement is running on the server through that URL.

Consuming the Data through a .Net Application

Consuming the data feed through a .Net application is very easy.  In your .Net application right click and use the Add Service Reference, then point the dialog to your same service.

Adding the service reference will actually generate a client side proxy for your application to communicate with that looks like a full blown entity framework model.  You can call it using code like a normal EF entities context, but the initialization must point to your Url.  I hard coded it in the code below, but in a normal app you would put this in the app.config to allow for easier management of the service endpoint.

static void Main(string[] args)
{
    VistaDBCommandsEntities cs = new 
                       VistaDBCommandsEntities(new 
                               Uri("http://localhost:1883/VistaDBCommandService.svc"));


    var result = (from c in cs.Commands
                  where c.Status.Description.Equals("Implemented") &&
                      c.Database.Description.Equals("VistaDB")
                  select new { c.SQLCommand, c.ExampleSyntax }).Take(5);

    foreach (var r in result)
    {
        Console.WriteLine(r.SQLCommand + " : " + r.ExampleSyntax);
    }

}

Note that the entities are not IDisposable, so you cannot put them in a using statement.

Visual Studio 2010 makes OData easy

The combination of WCF Data Services and Entity Framework makes it VERY easy to expose your data in a rest-ful manner over the web.  Take a look at the DataService options and you will find a very deep system for controlling who can query data, update, how many rows they can pull at once, etc. 

Discussions

10/06/2010 10:41 #

Eric

Matt,
  Under the "Browse to the Commands Entity" a couple of lines are cut off by the image.

EricB

Eric United States

10/06/2010 10:50 #

trackback

Exposing OData from an Entity Framework Model

Thank you for submitting this cool story - Trackback from DotNetShoutout

DotNetShoutout

10/06/2010 10:58 #

Eric

Matt,
    I have followed your example with success up to the point of "Browse to the Commands Entity", and so far all is working correctly.  However, when I try this command as the URL "http://localhost:1883/VistaDBCommandService.svc/Commands", I get a "HTTP 5000 Internal Server Error".

I know absolutely 0 about web applications, but am assuming that I have something configured incorrectly.

Any ideas what I may need to check/change to get this working?

Thanks,


EricB

Eric United States

10/06/2010 11:07 #

pingback

Pingback from topsy.com

Twitter Trackbacks for
        
        Exposing OData from an Entity Framework Model
        [infinitecodex.com]
        on Topsy.com

topsy.com

10/06/2010 11:12 #

Jason Short

Eric, actually I wrote this one.  And you have to change the port number depending upon your machine.  The localhost:xxxx will change everytime Visual Studio starts the web application.  So you have to launch the service in the browser from Visual Studio, and then look at the URL it output.

Jason Short United States

10/06/2010 11:14 #

Jason Short

"right click the service and say to view in a browser"

Then look at the URL.  And there are no lines cut off in Chrome or IE.  There are a bunch of blank lines added to prevent anything from being cut off.

Jason Short United States

10/06/2010 11:19 #

Eric

The writing sounded like Matt's.  

Interesting, in IE it doesn't cut off, but in Lunascape it does.  First time I have had trouble with Lunascape displaying differently than IE (that I know of).

I did the "view in browser", and am using the port that shows in the browser.  The initial "view in browser" works, it is just when I add the "Commands" at the end of the URL that I get the 500 error.

EricB

Eric United States

10/06/2010 11:24 #

Eric

Jason,
    For a Web Application, where should the License.licx file be located?

Eric

Eric United States

10/06/2010 11:28 #

js_vistadb

Commands() would only be if you have a table named commands in your EF model.  You should be able to run the browser against the service, and then select any of the models as a link displayed.  They are all relative links.

Look in the help file for licensing both a web application and a website.  The licenses.licx goes on the root of the site.  When you compile a web application it is compiled into the dll.  For a website you have to right click and select build licenses.  Yes, they are different for very esoteric reasons.

js_vistadb United States

11/06/2010 03:17 #

trackback

Exposing OData from an Entity Framework Model

Exposing OData from an Entity Framework Model

http://links.ginktage.com

16/06/2010 12:45 #

Eric

Jason,
    I figured it out (it was a problem with the license file).  The way I finally figured out what exception was being thrown was to add the following line to the servicename.svc.cs file in the InitialzeService method:

config.UseVerboseErrors=true;

This will show you the exact exception that is being thrown.

EricB

Eric United States

Discussions are closed