[Tutorial & Sample] Open complex type step by step with Web API 2.2 for OData v4.0
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:
- Query the metadata information of the book store.
- Query the books from the book store.
- 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:
- Microsoft.OData.Core, Microsoft.OData.Edm, Microsoft.Spatial are the OData v4 Dlls.
- 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.
Inline model dataFor simplicity we'll store all the data in memory using a BooksContext class which as you can see below has three books.
- The Press of Book1 has no dynamic properties.
- The Press of Book2 has two dynamic primitive properties.
- The Press of Book3 has one dynamic complex property.
Build the Edm ModelNow 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.
Build the controllerIt'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.
Build the clientFor 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:
Query the metadata
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 propertiesCustomers can now retrieve a single entity (and it’s dynamic properties) like this: // QueryEntity()
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.