{"id":153,"date":"2014-09-12T04:07:00","date_gmt":"2014-09-12T04:07:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2014\/09\/12\/tutorial-sample-odatauriparser-extension-support\/"},"modified":"2020-01-07T04:10:05","modified_gmt":"2020-01-07T11:10:05","slug":"tutorial-sample-odatauriparser-extension-support","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/tutorial-sample-odatauriparser-extension-support\/","title":{"rendered":"[Tutorial &amp; Sample] ODataUriParser Extension Support"},"content":{"rendered":"<p>This post is to guide you through the extension support of OData URI parser, which was added in <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.OData.Core\/\">ODataLib 6.7 release<\/a>.<\/p>\n<p>You can refer to the following article for basic usage of OData URI parser:<\/p>\n<ul>\n<li><a href=\"http:\/\/blogs.msdn.com\/b\/odatateam\/archive\/2014\/07\/04\/quick-guide-for-odata-uriparser.aspx\">[Tutorial &amp; Sample] Using ODataUriParser for OData V4<\/a><\/li>\n<\/ul>\n<p>All the demo code in this post has been put into <a href=\"https:\/\/github.com\/OData\/ODataSamples\">ODataSamples project<\/a>, you can check it out under the Components\/UriParser subfolder.<\/p>\n<h2>Background<\/h2>\n<p>The OData URI parser implements the logic for processing various URIs according to OData convention. As you may know, the Open Data Protocol (OData) V4 is described by a series of specification documents. Among them, the Uri parser is covered in <a href=\"https:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/odata-v4.0-part1-protocol.html\">Part1\u2013 Protocol<\/a>, <a href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/odata-v4.0-part2-url-conventions.html\">Part2\u2013 URL Conventions<\/a>, and <a href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/os\/abnf\/odata-abnf-construction-rules.txt\">OData ABNF Constructor Rule<\/a>.<\/p>\n<p>The protocol has defined relatively strict rules on what a valid OData URI should look like. For instance, identifiers should be case sensitive, and bound function calls should always use namespace qualified function name. Those rules are helpful for eliminating ambiguity and name conflict. The OData URI parser follows them, which in turn leads to a set of strong validation rules.<\/p>\n<p>On the other hand, there are some drawbacks, such as:<\/p>\n<ul>\n<li>Some existing services\/clients may have their APIs using case insensitive convention. It becomes a problem when porting to OData.<\/li>\n<li>Namespace qualified identifiers sometimes make the whole URI too long, and user may want to use the short name directly, provided that there are no name conflicts.<\/li>\n<li>Advanced users may even want to have the customized rules for parsing URIs.<\/li>\n<\/ul>\n<p>In order to deal with those issues, we added the extension framework for URI parser in ODataLib.<\/p>\n<h2>Overview<\/h2>\n<p>The basic idea for extending the OData URI parser is to expose some inner parsing procedures and allow users to override them.<\/p>\n<p>In general, we introduced a new class named ODataUriResolver, which exposes some parsing phrases, such as ResolveType and ResolveProperty. And ODataUriParser\/ODataQueryOptionParser now have a new property called Resolver, which accepts an ODataUriResolver instance. The user could choose to override the default behavior of ODataUriResolver and thus have their customized parser.<\/p>\n<p>User could choose to customize the following behaviors by overriding corresponding method on ODataUriResolver class:<\/p>\n<ul>\n<li>Resolving property name<\/li>\n<li>Resolving type name<\/li>\n<li>Resolving navigation source name<\/li>\n<li>Resolving operation import name<\/li>\n<li>Resolving bound operation name<\/li>\n<li>Resolving function parameters<\/li>\n<li>Resolving entity set key<\/li>\n<li>Resolving binary operator node elements<\/li>\n<\/ul>\n<p>One major scenario we want to enable is case insensitive. An option EnableCaseInsensitive in ODataUriResolver class is introduced to control the case behavior. In addition, two built in extension implementations are provided to support extended features such as unqualified function call, and prefix-free enum value. All those extensions would be discussed in following section.<\/p>\n<h2>Using built in extensions<\/h2>\n<h2>Case-insensitive support<\/h2>\n<p>There is an option on ODataUriResolver for case insensitive behavior. It controls both built in identifiers ($filter, eq, etc.) and user metadata (property name, type name). A detailed scope could be found on the <a href=\"http:\/\/blogs.msdn.com\/b\/odatateam\/archive\/2014\/09\/05\/announcement-odatalib-6-7-0-release.aspx\">ODataLib 6.7 release note<\/a>. To enable it, Resolver property needs to be set to an ODataUriResolver instance(we use default implementation here) with EnableCaseInsensitive option turned on.<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/6044bb6eafb61efd7561.js\"><\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>Unqualified function call support<\/h2>\n<p>Unqualified function call is supported by UnqualifiedODataUriResolver class, which inherits from ODataUriResolver. It enables bound function call without namespace in both path and query options. When conflicts are found, for example\nif there\u2019re two functions with same name and signature but in different namespaces, the parser would throw an exception.<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/8356357097d6536f2edf.js\"><\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>Prefix-free enum value support<\/h2>\n<p>Prefix-free enum value is supported by StringAsEnumResolver class, which also inherits from ODataUriResolver. According to OData V4 specification, enum values should be prefixed by enum type name. In some cases, we already know what the expected type is, thus the type name is redundant as it could be inferred. For example, we have a function accepting an enum parameter, then in the function call URI, the parameter value could be written as a string. When evaluating the parameter, we can parse it to the expected enum type.<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/5ad099b726c43169bbce.js\"><\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>Write your own extension<\/h2>\n<p>There are other scenarios that built-in extension did not cover directly. In this case, you can choose to extend the URI parser by writing your own resolver.<\/p>\n<h2>Combination of built-in extensions<\/h2>\n<p>One common case is when user want to enable unqualified function call and prefix-free enum at the same time. Thus you can write a resolver class which internally wraps those two resolver. You can find the <a href=\"https:\/\/github.com\/odata\/\">source code<\/a> for AllInOneResolver class in the <a href=\"https:\/\/github.com\/OData\/ODataSamples\">sample project<\/a>. Here is the demo for its usage:<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/09e1860411b8feda8659.js\"><\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>Write customized extensions from scratch<\/h2>\n<p>If there is no existing extension meets your requirement, it is also easy to write your own extension from scratch. Here is an example for operator overloading extension.<\/p>\n<p>In some programming languages, it supports the syntax for multiplying a string and a number, which means duplicating the string by N times. For example \u20183\u2019*5 would produce \u201833333\u2019. With OData URI parser, when you write<em> \u20183\u2019 mul 5<\/em> in query option, it would be treated as invalid as mul operator does not support Edm.String and Edm.Int32 as operands. In this case, you could write your own extension for it:<\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/5245d34e73d2bfe6a3e0.js\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is to guide you through the extension support of OData URI parser, which was added in ODataLib 6.7 release. You can refer to the following article for basic usage of OData URI parser: [Tutorial &amp; Sample] Using ODataUriParser for OData V4 All the demo code in this post has been put into ODataSamples [&hellip;]<\/p>\n","protected":false},"author":516,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[54],"class_list":["post-153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","tag-odatalib"],"acf":[],"blog_post_summary":"<p>This post is to guide you through the extension support of OData URI parser, which was added in ODataLib 6.7 release. You can refer to the following article for basic usage of OData URI parser: [Tutorial &amp; Sample] Using ODataUriParser for OData V4 All the demo code in this post has been put into ODataSamples [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/153","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\/516"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=153"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/153\/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=153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}