{"id":223,"date":"2014-07-20T18:59:00","date_gmt":"2014-07-20T18:59:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2014\/07\/20\/tutorial-sample-open-complex-type-step-by-step-with-web-api-2-2-for-odata-v4-0\/"},"modified":"2020-01-07T07:09:02","modified_gmt":"2020-01-07T14:09:02","slug":"tutorial-sample-open-complex-type-step-by-step-with-web-api-2-2-for-odata-v4-0","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/tutorial-sample-open-complex-type-step-by-step-with-web-api-2-2-for-odata-v4-0\/","title":{"rendered":"[Tutorial &amp; Sample] Open complex type step by step with Web API 2.2 for OData v4.0"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Recently, Microsoft officially announced Web API 2.2 for OData v4 via the blog post <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2014\/07\/02\/announcing-the-release-of-asp-net-mvc-5-2-web-api-2-2-and-web-pages-3-2.aspx\">Announcing the Release of ASP.NET MVC 5.2, Web API 2.2 and Web Pages 3.2<\/a>. In this release, a new feature named open\u00a0complex type is introduced.<\/p>\n<p>As the <a href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/odata-v4.0-part1-protocol.html\"><em>ODL v4 spec<\/em><\/a><em> says: Open complex types are keyless named structured types consisting of a set of <strong>declared<\/strong> and <strong>dynamic<\/strong> (un-declared) properties.<\/em><\/p>\n<p>Open complex types allow customers to add undeclared properties in the payload. And in the future they can use these properties in queries.<\/p>\n<p>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\u2019s get started.<\/p>\n<div>\n<h2><strong>BookStore<\/strong> Console Application<\/h2>\n<p>For simplicity, we\u2019ll\u00a0start by creating a simple console application named <strong>BookStore<\/strong>. In this console application, we\u2019ll create an inline Web API OData Service to provide the basic functionality\u00a0of a book store:<\/p>\n<ol>\n<li>Query the metadata information of the book store.<\/li>\n<li>Query the books from the book store.<\/li>\n<li>Create new books into the book store.<\/li>\n<\/ol>\n<div>\n<h2>Install the Nuget package<\/h2>\n<p>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 \u201cReferences\u201d in the <strong>BookStore<\/strong> project and select \u201cManage Nuget Packages\u201d in the Nuget Packages Management dialog. You should see:<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/5342.Step1.png\"><img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/5342.Step1.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>In the above dialog, search and select \u201cMicrosoft ASP.NET Web API 2.2 for OData v4.0\u201d package and click the install button to install the package into the console application. After being installed, the updated references are the follows:<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/8688.step2.png\"><img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/8688.step2.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>Where:<\/p>\n<ol>\n<li><strong>Microsoft.OData.Core<\/strong>, <strong>Microsoft.OData.Edm<\/strong>, <strong>Microsoft.Spatial<\/strong> are the OData v4 Dlls.<\/li>\n<li><strong>System.Web.OData<\/strong> is the Web API 2.2 Dll.<\/li>\n<\/ol>\n<p>And the packages.config has the following values:<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/8322.step3.png\"><img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/01\/63\/30\/8322.step3.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<h2>Build the open complex type model<\/h2>\n<h2>CLR type definition<\/h2>\n<p>For developers, it\u2019s quite easy to define a model with open complex type. You should only add an extra property with <em><strong>IDictionary&lt;string, object&gt;<\/strong><\/em> in your CLR class.<\/p>\n<p>For the <strong>BookStore<\/strong> application, we&#8217;ll create a couple of C# classes to build the model. First of all, add a new folder in the solution named \u201cModels\u201d. In the \u201cModels\u201d folder, add the following classes:<\/p>\n<div>\n<p class=\"CodeCxSpFirst\">\/\/ CLR classes:<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/bfad041383baf00fd11b.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">Where in OData terms:<\/p>\n\n\n\n<\/div>\n\n\n\n\n<ul>\n \t\n\n<li><strong>Book<\/strong> \u00a0is an entity type.<\/li>\n\n\n \t\n\n<li><strong>Press <\/strong>is an open complex type, because it has an extra property named <em>DynamicProperties<\/em> as <em>IDictionary&lt;string, object&gt;<\/em>.<\/li>\n\n\n \t\n\n<li><strong>Address<\/strong> is an open-less complex type.<\/li>\n\n\n \t\n\n<li><strong>Category<\/strong> is an Enum type.<\/li>\n\n\n<\/ul>\n\n\n<strong><span style=\"color: #ff0000;\">Note<\/span><\/strong>: The <em>DynamicProperties<\/em> property in the <strong>Press<\/strong> type is a container used to contain the dynamic properties. In WebAPI 2.2 for OData v4, a complex type with an <em>IDictionary&lt;string, object&gt;<\/em> property will be built as an open complex type.\n\n\n<h2>Inline model data<\/h2>\n\n\nFor simplicity we'll store all the data in memory using a <strong>BooksContext<\/strong> class which as you can see below has three books.\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ BooksContext.cs<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/949546e1e1469783c573.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n<\/div>\n\n\nWhere:\n\n\n<ol>\n \t\n\n<li>The <strong>Press<\/strong> of Book1 has no dynamic properties.<\/li>\n\n\n \t\n\n<li>The <strong>Press<\/strong> of Book2 has two dynamic primitive properties.<\/li>\n\n\n \t\n\n<li>The <strong>Press<\/strong> of Book3 has one dynamic complex property.<\/li>\n\n\n<\/ol>\n\n\n\n\n<h2>Build the Edm Model<\/h2>\n\n\nNow it\u2019s easy to build \u00a0the Edm Model like this:\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ GetEdmModel()<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/8ce2e8a3fdf774f17d3d.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<p class=\"CodeCxSpFirst\"><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: The convention model builder won\u2019t automatically add the <strong>Address<\/strong> type because there are no properties of the Book or the related <strong>Press<\/strong> classes that explicitly reference the <strong>Address<\/strong> class. However we plan on using <strong>Address<\/strong> in our open <strong>Press<\/strong> class, so we need to add it explicitly to the model.<\/p>\n\n\n\n<\/div>\n\n\n\n\n<h2>Build the controller<\/h2>\n\n\nIt's time to build the controller to implement the OData routing. Add a new folder named \"Controllers\" in the <strong>BookStore<\/strong> project. In this folder, add a C# class named <strong>BooksController<\/strong> and derived it from <strong>ODataController<\/strong>. In this class, we'll add a private instance of <strong>BooksContext<\/strong> to play the DB role like this:\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ BooksController.cs<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/19e6b097be71eb87577e.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<p class=\"CodeCxSpFirst\"><span style=\"color: #ff0000;\"><strong>Note<\/strong><\/span>: 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\u2019s supported interactions if needed.<\/p>\n\n\n\n<\/div>\n\n\n\n\n<h2>Build the client<\/h2>\n\n\nFor simplicity, we'll build the client in the same console application. First, we change the <strong>Program<\/strong> class name to <strong>BookStoreApp<\/strong> class and use it to serve as our client. By adding the following method to create the instance of <strong>HttpClient<\/strong>:\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ GetClient()<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/9e8313e1b0f13f41c0c2.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<h2>Query the metadata<\/h2>\n\n\n<\/div>\n\n\nFor customers to use the OData service, they first need to query the metadata document. Here\u2019s how you can do that:\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ QueryMetadata()<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/cd6d8a1b05d251517c6b.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<p class=\"CodeCxSpFirst\">The resulting metadata document is below. For a customer, he can find the complex type \u201c<strong>Press<\/strong>\u201d has an attribute named <strong>OpenType<\/strong> and its value is true, while the complex type <strong>Address<\/strong> doesn\u2019t have such attribute. Most importantly, \u201c<strong>Press<\/strong>\u201d complex type has only <span style=\"color: #0000ff;\"><strong>THREE<\/strong><\/span> declared properties named \u201c<em>Name, Web, Category<\/em>\u201d. The customer doesn\u2019t know anything about the \u201c<em>DynamicProperties<\/em>\u201d property, because this is merely an implementation detail.<\/p>\n\n\n\n<\/div>\n\n\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">\/\/ Metadata document<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/d8c10810fabeeb53ff83.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n<\/div>\n\n\n\n\n<h2>Query the entity with the dynamic properties<\/h2>\n\n\nCustomers can now retrieve a single entity (and it\u2019s dynamic properties) like this:\n\n\/\/ QueryEntity()\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/63576e234e76897a7c82.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">The payload of the entity with dynamic properties should be:<\/p>\n\n\n\n\n<p class=\"CodeCxSpFirst\">\/\/ Payload<\/p>\n\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/4554a08ac7a3bc8cf977.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n<\/div>\n\n\n\n\n<div>\n\n\n<p class=\"CodeCxSpFirst\">Where, the customer can find out that the <strong>Press<\/strong> property of Book('<span style=\"color: #ff0000;\">978-1-107-63706-1<\/span>\u2019) has four properties (three declared properties and one dynamic property). The name of dynamic property is \u201cAddress\u201d and its type is <strong>#BookStore.Address<\/strong>.<\/p>\n\n\n\n<\/div>\n\n\n\n\n<h2>Create an entity with dynamic properties<\/h2>\n\n\nThe 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:\n\n<strong><em>POST<\/em><\/strong><em> ~\/odata\/Books<\/em>\n\n<em><strong>Content-Type<\/strong>: application\/json<\/em>\n\n<strong><em>Content:<\/em><\/strong>\n\n<script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/32d6b75106d2f6e1e7dc.js\">\/\/ <![CDATA[\n\n\/\/ ]]&gt;<\/script>\n\n\n<h2>Summary<\/h2>\n\n\nThe open complex type feature included in Web API 2.2 for OData v4\u00a0 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.\u00a0 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.\n\nThanks.\n\n<\/div>\n\n\n<\/div>\n\n\n<\/div>\n\n\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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\u00a0complex type is introduced. As the ODL v4 spec says: Open complex types are keyless named structured types consisting [&hellip;]<\/p>\n","protected":false},"author":514,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-223","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata"],"acf":[],"blog_post_summary":"<p>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\u00a0complex type is introduced. As the ODL v4 spec says: Open complex types are keyless named structured types consisting [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/514"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=223"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/223\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}