At TechEd I got a lot of questions about how to expose Data as OData

By now you probably know you can use Data Services and the Entity Framework to expose data from a database as an OData Service. You might even know you can use Data Services with a custom Data Service Provider to expose arbitrary data from anywhere.

But did you know about the Data Services Reflection provider?.

Turns out reflection provider  is VERY simple to use.

To show you just how simple I am going to create an odata service to expose some in memory data.

First you need some data, so how about this topical data:

[EntityPropertyMapping("Name",
SyndicationItemProperty.Title,
SyndicationTextContentKind.Plaintext,
false)]
[EntityPropertyMapping("Odds",
SyndicationItemProperty.Summary,
SyndicationTextContentKind.Plaintext,
false)]
public class Team {    
public static List<Team> Teams = new List<Team>{
         new Team {ID = 1, Name = "New Zealand", Odds = "1:1000"},
         new Team {ID = 2, Name = "Paraquay", Odds = "1:50"},
         …     };


    public int ID{get;set;}
    public string Name {get;set;}
    public string Odds { get; set; }
}

[DataServiceKey("Name")]
[EntityPropertyMapping("Name",
SyndicationItemProperty.Title,
SyndicationTextContentKind.Plaintext,
false)]
public class Group
{
    public static List<Group> Groups = new List<Group>{ 
      new Group { 
         Name = "A", 
         Teams = new List<Team>{ 
            Team.Teams[0],
             Team.Teams[1],
             Team.Teams[2],
             Team.Teams[3]
         }
       },     
new Group {
         Name = "B",
         Teams = new List<Team>{
             Team.Teams[4],
             Team.Teams[5],
             Team.Teams[6],
             Team.Teams[7]
          }
       },
      …
    };
    public string Name {get;set;}
    public List<Team> Teams {get;set;}
}

Notice the use of the [DataServiceKey] and [EntityPropertyMapping] attributes:

  • [DataServiceKey] tells Data Services which property(s) is the key. This is only required if the key isn’t ID or {ClassName}ID.
  • [EntityPropertyMapping] tells Data Services to map the property to a standard atom element. This is not required – but it is a best practice – it makes the resulting feed easier to read in a browser.

Next you need a class to act as your Data Source. Data Services will expose all the IQueryable properties as Feeds and infer types for all the types exposed by those Feeds.

So if I want two feeds, to expose Groups and Teams from the world cup, I’d do it like this:

public class WorldCupData
{
     public IQueryable<Team> Teams{
        get{
            return Team.Teams.AsQueryable();
        }
    }
     public IQueryable<Group> Groups{
        get{ 
           return Group.Groups.AsQueryable();

       }
     }
}

Now all you need to do is create the Data Service, and expose our sets. Simply add a WCF Data Service to you web application and modify the generated code to look like this:

public class WorldCup : DataService<WorldCupData>
{
     // This method is called only once to initialize service-wide policies.
     public static void InitializeService(DataServiceConfiguration config)     {
         config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
         config.SetEntitySetPageSize("*", 100);
         config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
     }
}

That’s it you are done:

ReflectionProvider

A couple of points worth noting:

  • This service is read-only. If you want to make it read-write you have to implement IDataServiceUpdateProvider.
  • In this example the data comes from in-memory arrays, however if you have an IQueryable that supports it your data can come from anywhere.
  • Yes I know my data is all wrong, I’m writing this on a SouthWest flight from New Orleans to Denver with no internet. But thankfully there is a real OData Service for the World Cup here.

Enjoy.