Determining if a Service is OData compliant

This document contains code samples and is considered an intermediate to advanced topic. A working knowledge of Visual Studio, the C# programming language and respective terminology is assumed.

The OData specification was originally described by the Microsoft corporation under the Microsoft Open Specification Promise. However, compliance to a standard can be subjective and may mean that not all services are fully compliant or contain errors in their structure. Due to this, the OData Service Broker may display unexpected behavior if the service is not fully OData compliant. The steps in this topic explain how to test an OData service for compliance before attempting to register an OData Service Instance or generating and using SmartObjects based on the service.

The product’s OData Broker uses the same code generation technology as Visual Studio: the OData Client Code Generation Tool (http://odata.github.io/odata.net/#OData-Client-Code-Generation-Tool).

The steps described here also aid when trying to determine whether a problem resides with the OData service itself or with the OData service broker. Apart from the steps below, also see http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/calling-an-odata-service-from-a-net-client for more resources on testing OData compliance. The full OData specification can be found at http://www.odata.org/documentation/odata-version-3-0/. This external page is subject to change over time however, so you may need to search the site to find the documents describing the complete OData spec

Required Resources

  • Visual Studio (a console application will be used to determine if the service is OData compliant)
  • The OData service URL of the service you intend to test

If you wish to test this approach with a known, working service, paste the following URL into the browser of your choice:
http://services.odata.org/V3/(S(readwrite))/OData/OData.svc/
This will generate a sample “readwrite” OData service that you can use for testing this approach.

Results in the following sample service URL:

Testing the Service

To get started, you need to create a Service Reference within a Visual Studio project.

  1. Create a new Console Application project in Microsoft Visual Studio.
  2. From the Project Explorer, right on click on References and select Add Service Reference
  1. The Add Service Reference dialog appears
  1. Enter the OData service URL into the field labelled Address
  2. Enter a Namespace name for example: ODataService
  3. Click Go
  1. There may be a delay as the data is downloaded, should it be successful you will be able to view the Services in the tree view labelled Services. Click OK to complete.
  1. If successful, the project explorer will update as shown below. If it is not successful, it is likely that there is some underlying issue or format in the service you are trying to connect to. If Visual Studio is not able to connect to the OData service using this approach, then the product will not be able to, either.
  1. Add the following references to you project
  1. System.Net
  2. Namespace + Service Name ie: TestODataService.ODataService
  1. The goal from this point forward is to determine the level of compliance your service has with OData. If you’ve successfully made it to this step then some major hurdles have already been cleared. They include having a $metadata document available and having entities which ALL have primary keys among others.
  1. Next you will need to write some code to verify that the service can perform the operations you wish to expose. The code will depend on the service you intend to consume. The code sample below illustrates testing the generic OData service URL described in the required resources section.
    Copy

    Testing the generic OData service URL described in the required resources section

    namespace TestODataService {
        class Program {
            static void Main(string[] args) {
                DemoService demoService = new DemoService(new Uri("http://services.odata.org/V3/(S(jtqzg2omvsfijmswesaplibf))/OData/OData.svc/"));

                //Fill this property in with your relevant credentials.
                demoService.Credentials = CredentialCache.DefaultNetworkCredentials;

                //Test listing on entities
                var products = demoService.Products.ToList();
                var categories = demoService.Categories.ToList();
                var suppliers = demoService.Suppliers.ToList();
                //etc....
                //Test loading an entity
                var product5 = demoService.Products.Where(x = >x.ID == 5).FirstOrDefault();

                //Test updating an entity
                product5.Name = "UpdatedTestProduct";
                demoService.UpdateObject(product5);
                demoService.SaveChanges();

                //Test creating an entity
                Product newProduct = new Product() {
                    ID = 253,
                    //The primary key(s) of the entity must always be set
                    //(in this case the key is the ID property)
                    Name = "NewTestProduct",
                    Description = "Testing",
                    Rating = 8
                    /* etc... */
                };

                //For inherited types use the BaseType
                //(e.g. when testing the inherited entity DemoService.FeaturedProduct, use
                //typeof(DataServiceQuery<Product>) as shown)
                var productsQueryType = typeof(DataServiceQuery < Product > );
                var entitySetName = typeof(DemoService).GetProperties().Where(x = >x.PropertyType == productsQueryType).FirstOrDefault().Name;
                demoService.AddObject(entitySetName, newProduct);
                demoService.SaveChanges();
            }
        }
    }
  1. The above program can be modified to test any OData service that isn’t behind a client certificate or that requires OAuth. Should any of the operations fail, then there are a few things to check.
  1. First, make sure your service allows full access to each entity. It’s perfectly acceptable to allow reads but not writes and vice-versa.
  2. Services can also restrict the number of records you can pull on each request, so the entire entityset may not come back when listing. Filtering or paging code would need to be written in this sample to overcome this. The OData service broker accommodates this.
  3. Another source of strange behavior could be an attached resource stream on the entity. If this is the case then the error should be fairly clear and indicate that no media or named resource stream was set.
  4. Bad credentials could also be a source of issues. If your service needs more advanced authentication such as OAuth or an X.509 client certificate, then additional code would need to be written into the sample above. For OAuth you can set the Bearer token in the headers by adding to the SendingRequest2 event on the DataServiceContext (DemoService class in this example). For X.509 certificates the code necessary to test with them is outside of the scope of this document. It involves compiling a dll at runtime using the EntityClassGenerator.
  1. If all the points in step 8 have been checked but you still experience trouble. then there is a strong likelihood that your service is not OData compliant in some way, for example that there may be invalid characters in the service or service description. To determine why the service is not compliant, you will need to consult the OData spec.