First look at OData

ODataLogo-96I’ve heard about OData back in 2012 but never used it. Now I might have a use case for OData and want to explore it. Below are the parts of my sample WCF DataService project.
Every part has the exceptions and how I solved them.


My first project contains the entities of the sample project. A Survey and the Reports on it. Master-Detail with the surveyId stored in the Report.


On data context type ‘SurveyProvider’, there is a top IQueryable property ‘Surveys’ whose element type is not an entity type. Make sure that the IQueryable property is of entity type or specify the IgnoreProperties attribute on the data context type to ignore this property.


This exception is from the datacontext in the next part, but the cause is the missing [DataServiceKey(“Id”)] on the entities.


public partial class Survey {
    public string Id { get; set; }
    public string SurveyName { get; set; }
    public virtual ICollection<Report> Reports { get; set; }
public partial class Report {
    public string Id { get; set; }
    public DateTime Created { get; set; }
    public string SurveyId { get; set; }
    public virtual Survey Survey { get; set; }


The data project is for the reflection provider that holds the (test)data. All data is stored in lists.


HTTP 204 no content


Property is null in LoadProperty. Make sure the DataContext provides a value for the Master/Detail.


public class SurveyProvider {
    private List<Survey> surveys = new List<Survey> {
        new Survey { Id = "1", SurveyName = "Flight" }
    private List<Report> reports = new List<Report> { 
        new Report { Id = "1", SurveyId = "1", Created = new DateTime(2015,1,1,10,0,0) },
        new Report { Id = "2", SurveyId = "1", Created = new DateTime(2015,1,1,11,0,0) },
        new Report { Id = "3", SurveyId = "1", Created = new DateTime(2015,1,1,12,0,0) },
        new Report { Id = "4", SurveyId = "1", Created = new DateTime(2015,1,1,13,0,0) },
        new Report { Id = "5", SurveyId = "1", Created = new DateTime(2015,1,1,14,0,0) },
    public SurveyProvider() {
        surveys.ForEach(s => s.Reports = reports.Where(r => r.SurveyId == s.Id).ToList());
        reports.ForEach(r => r.Survey = surveys.First(s => s.Id == r.SurveyId));
    public IQueryable<Survey> Surveys {
        get { return surveys.AsQueryable(); }
    public IQueryable<Report> Reports {
        get { return reports.AsQueryable(); }


For easy debugging and trouble shooting enable the extra information on exceptions for the DataService. (See the code)

Also look at the metadata with the $metadata query option: http://localhost:53021/SurveyServiceOData.svc/$metadata

Host this in IIS to capture all traffic, because you’ll miss the lazy loading when hosting in IISExpress.


[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class SurveyServiceOData : DataService<SurveyProvider> {
    public static void InitializeService(DataServiceConfiguration config) {
        config.UseVerboseErrors = true;
        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
        config.DataServiceBehavior.MaxProtocolVersion = 



HTTP Error 400. The request hostname is invalid.
or no traffic captured with fiddler.


Use the localhost.fiddler when hosting in IISExpress.

var uri = new Uri("http://localhost.fiddler:53021/SurveyServiceOData.svc");


The remote name could not be resolved: ‘localhost.fiddler’.


Set the proxy to fiddler.

  <!-- other settings in app.config -->
    <defaultProxy enabled="true" >
      <proxy proxyaddress="http://localhost:8888"/>


The MaxDataServiceVersion ‘2.0’ is too low for the response. The lowest supported version is ‘3.0’.


Make sure the versions of the DataService and Client match. See also the InitializeService method of the DataService.

var ctx = new DataServiceContext(uri, DataServiceProtocolVersion.V3);


A property with name ‘Reports’ on type ‘Reporting.Entities.Survey’ has kind ‘Structural’, but it is expected to be of kind ‘Navigation’.


install-package EntityFramework


static void Main(string[] args) {
    // use MachineName
    var uri = new Uri("http://localhost.fiddler:53021/SurveyServiceOData.svc");
    var context = new DataServiceContext(uri, DataServiceProtocolVersion.V3);
    var survey = context.CreateQuery<Survey>("Surveys").First();
    Console.WriteLine("Found survey {0} with {1} reports",
        survey.SurveyName, survey.Reports == null ? "null" : survey.Reports.Count.ToString());
    var response = context.LoadProperty(survey, "Reports");
    Console.WriteLine("LoadProperty Reports on Survey returned {0}", response.StatusCode);
    Console.WriteLine("Found survey {0} with {1} reports",
        survey.SurveyName, survey.Reports.Count.ToString());
    var pointInTime = new DateTime(2015, 1, 1, 12, 0, 0);
    var report = context.CreateQuery<Report>("Reports")
            .Where(r => r.SurveyId == "1")
            .Where(r => r.Created == pointInTime)
    Console.WriteLine("Found report on {0} for Survey {1}",
            report.Created, report.Survey == null ? "null" : report.Survey.SurveyName);
    response = context.LoadProperty(report, "Survey");
    Console.WriteLine("LoadProperty Survey on Report returned {0}", response.StatusCode);
    Console.WriteLine("Found report on {0} for Survey {1}", report.Created, report.Survey.SurveyName);


The potential of WCF data service is there. Just expose the data and let the clients filter and query what they need.


Demo project for download with all the documentation
Custom Data Service Providers on MSDN

About erictummers

Working in a DevOps team is the best thing that happened to me. I like challenges and sharing the solutions with others. On my blog I’ll mostly post about my work, but expect an occasional home project, productivity tip and tooling review.
This entry was posted in Development and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.