Introduction

Recently, Microsoft officially announced Web API 2.2 for OData v4 via the blog post Announcing the Release of ASP.NET MVC 5.2, Web API 2.2 and Web Pages 3.2. In this release, a new feature named open complex type is introduced.

As the ODL v4 spec says: Open complex types are keyless named structured types consisting of a set of declared and dynamic (un-declared) properties.

Open complex types allow customers to add undeclared properties in the payload. And in the future they can use these properties in queries.

This blog is intended to provide a step by step guide for you to use the open complex types with Web API 2.2 for OData v4.0. Let’s get started.

BookStore Console Application

For simplicity, we’ll start by creating a simple console application named BookStore. In this console application, we’ll create an inline Web API OData Service to provide the basic functionality of a book store:

  1. Query the metadata information of the book store.
  2. Query the books from the book store.
  3. Create new books into the book store.

Install the Nuget package

Once the empty console application has been created, the first thing is to install the Web API 2.2 for OData v4.0 Nuget package from Nuget.org. On the solution explorer, right click on “References” in the BookStore project and select “Manage Nuget Packages” in the Nuget Packages Management dialog. You should see:

 

In the above dialog, search and select “Microsoft ASP.NET Web API 2.2 for OData v4.0” package and click the install button to install the package into the console application. After being installed, the updated references are the follows:

 

Where:

  1. Microsoft.OData.Core, Microsoft.OData.Edm, Microsoft.Spatial are the OData v4 Dlls.
  2. System.Web.OData is the Web API 2.2 Dll.

And the packages.config has the following values:

Build the open complex type model

CLR type definition

For developers, it’s quite easy to define a model with open complex type. You should only add an extra property with IDictionary<string, object> in your CLR class.

For the BookStore application, we'll create a couple of C# classes to build the model. First of all, add a new folder in the solution named “Models”. In the “Models” folder, add the following classes:

// CLR classes:

Where in OData terms:

  • Book  is an entity type.
  • Press is an open complex type, because it has an extra property named DynamicProperties as IDictionary<string, object>.
  • Address is an open-less complex type.
  • Category is an Enum type.

Note: The DynamicProperties property in the Press type is a container used to contain the dynamic properties. In WebAPI 2.2 for OData v4, a complex type with an IDictionary<string, object> property will be built as an open complex type.

Inline model data

For simplicity we'll store all the data in memory using a BooksContext class which as you can see below has three books.

// BooksContext.cs

Where:

  1. The Press of Book1 has no dynamic properties.
  2. The Press of Book2 has two dynamic primitive properties.
  3. The Press of Book3 has one dynamic complex property.

Build the Edm Model

Now it’s easy to build  the Edm Model like this:

// GetEdmModel()

Note: The convention model builder won’t automatically add the Address type because there are no properties of the Book or the related Press classes that explicitly reference the Address class. However we plan on using Address in our open Press class, so we need to add it explicitly to the model.

Build the controller

It's time to build the controller to implement the OData routing. Add a new folder named "Controllers" in the BookStore project. In this folder, add a C# class named BooksController and derived it from ODataController. In this class, we'll add a private instance of BooksContext to play the DB role like this:

// BooksController.cs

Note: While this controller only supports Querying Books, Getting a single Book by key and Creating a new Book, you can easily add additional methods to implement the rest of OData’s supported interactions if needed.

Build the client

For simplicity, we'll build the client in the same console application. First, we change the Program class name to BookStoreApp class and use it to serve as our client. By adding the following method to create the instance of HttpClient:

// GetClient()

Query the metadata

For customers to use the OData service, they first need to query the metadata document. Here’s how you can do that:

// QueryMetadata()

The resulting metadata document is below. For a customer, he can find the complex type “Press” has an attribute named OpenType and its value is true, while the complex type Address doesn’t have such attribute. Most importantly, “Press” complex type has only THREE declared properties named “Name, Web, Category”. The customer doesn’t know anything about the “DynamicProperties” property, because this is merely an implementation detail.

// Metadata document

Query the entity with the dynamic properties

 Customers can now retrieve a single entity (and it’s dynamic properties) like this:  

 // QueryEntity()

The payload of the entity with dynamic properties should be:

// Payload

Where, the customer can find out that the Press property of Book('978-1-107-63706-1’) has four properties (three declared properties and one dynamic property). The name of dynamic property is “Address” and its type is #BookStore.Address.

Create an entity with dynamic properties

The customer can post an entity with dynamic properties to the service. The code is similar to above. In this case the request looks like this:

POST ~/odata/Books

Content-Type: application/json

Content:

Summary

The open complex type feature included in Web API 2.2 for OData v4  provides a very easy way for customers to post their customized properties to the data service and allow them to be queried and retrieved in the future.  We believe open complex type support is a really useful feature for modelling real world problems and in the future, after we add open entity type and the dynamic collection property support to the next release of Web API OData, it will be even better.

Thanks.