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.
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:
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:
And the packages.config has the following values:
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:
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.
For simplicity we'll store all the data in memory using a BooksContext class which as you can see below has three books.
Now it’s easy to build the Edm Model like this:
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.
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:
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.
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:
For customers to use the OData service, they first need to query the metadata document. Here’s how you can do that:
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
Customers can now retrieve a single entity (and it’s dynamic properties) like this:
The payload of the entity with dynamic properties should be:
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.
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:
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.