{"id":5892,"date":"2025-08-22T02:30:54","date_gmt":"2025-08-22T09:30:54","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/odata\/?p=5892"},"modified":"2025-08-22T02:30:54","modified_gmt":"2025-08-22T09:30:54","slug":"odata-net-9-preview-release","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/odata-net-9-preview-release\/","title":{"rendered":"OData .NET (ODL) 9 Preview Release"},"content":{"rendered":"<article>We\u2019re happy to announce that OData .NET (ODL) 9 Preview 2 has been officially released and is available on NuGet:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.OData.Core\/9.0.0-preview.2\">Microsoft.OData.Core 9.0.0 Preview 2<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.OData.Edm\/9.0.0-preview.2\">Microsoft.OData.Edm 9.0.0 Preview 2<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Spatial\/9.0.0-preview.2\">Microsoft.Spatial 9.0.0 Preview 2<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.OData.Client\/9.0.0-preview.2\">Microsoft.OData.Client 9.0.0 Preview 2<\/a><\/li>\n<\/ul>\n<h2>What\u2019s New in OData .NET (ODL) 9 Preview 1 &amp; 2<\/h2>\n<p>The OData .NET (ODL) 9.0 previews introduce a set of important changes and cleanup efforts to modernize the library,\nalign with .NET\u2019s evolving runtime, and simplify the OData developer experience. Below, we\u2019ll go through the notable\nchanges included in the first two preview releases.<\/p>\n<section>\n<h3>Targeting .NET 10 Preview<\/h3>\n<p>ODL now builds against .NET 10 preview, ensuring compatibility with the upcoming runtime. This helps early adopters\nvalidate OData workloads on the latest platform.<\/p>\n<\/section>\n<section>\n<h3>Removed JSONP Support<\/h3>\n<p>JSONP (JSON with Padding) was an early workaround for browsers\u2019 same-origin policy before CORS became widely adopted.\nIt allowed a client to request JSON data from another domain by wrapping the payload inside a JavaScript function call.<\/p>\n<p>For example, consider a normal OData JSON response:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"@odata.context\": \"http:\/\/localhost\/$metadata#Orders\",\r\n  \"value\": [\r\n    { \"Id\": 1, \"Status\": \"Pending\" },\r\n    { \"Id\": 2, \"Status\": \"Shipped\" }\r\n  ]\r\n}<\/code><\/pre>\n<p>With JSONP enabled and a callback function defined, the same response could be returned as:<\/p>\n<pre class=\"prettyprint language-javascript\"><code class=\"language-javascript\">processOrders({\r\n  \"@odata.context\": \"http:\/\/localhost\/$metadata#Orders\",\r\n  \"value\": [\r\n    { \"Id\": 1, \"Status\": \"Pending\" },\r\n    { \"Id\": 2, \"Status\": \"Shipped\" }\r\n  ]\r\n});<\/code><\/pre>\n<p>This allowed the client\u2019s browser to execute the function <code>processOrders<\/code> with the JSON payload as its\nargument, bypassing cross-domain restrictions.<\/p>\n<h4>Why It Was Removed<\/h4>\n<ul>\n<li><strong>Security concerns<\/strong>: JSONP allows arbitrary JavaScript execution, which can be exploited in XSS-style attacks.<\/li>\n<li><strong>Superseded by CORS<\/strong>: Modern browsers and frameworks natively support Cross-Origin Resource Sharing (CORS), which provides a secure and standards-based way to enable cross-domain requests.<\/li>\n<li><strong>Low usage<\/strong>: Very few ODL consumers relied on JSONP in recent years.<\/li>\n<\/ul>\n<p>By removing JSONP support, ODL 9 reduces attack surface and simplifies the codebase, without impacting the majority of\nmodern OData clients. Developers needing cross-domain access should instead configure CORS, which is the modern, secure\nalternative.<\/p>\n<\/section>\n<section>\n<h3>Case-Insensitive URI Resolver by Default<\/h3>\n<p>Previously, consumers had to explicitly enable case-insensitive handling for query options like <code>$filter<\/code>,\n<code>$select<\/code>, etc.<\/p>\n<p>According to the\n<a href=\"https:\/\/docs.oasis-open.org\/odata\/odata\/v4.01\/odata-v4.01-part2-url-conventions.html\">OData V4.01 specification<\/a>,\nservices <strong>MUST support case-insensitive system query option names<\/strong>, whether or not they are prefixed with\n<code>$<\/code>.<\/p>\n<p>ASP.NET Core OData already complies with this requirement by injecting a case-insensitive\n<a href=\"https:\/\/github.com\/OData\/AspNetCoreOData\/blob\/1368836752963d88e920d9508d94807eb995894b\/src\/Microsoft.AspNetCore.OData\/ODataOptions.cs#L326-L329\"><code>UnqualifiedODataUriResolver<\/code><\/a>\nby default. To ensure consistent behavior across the OData ecosystem, ODL now defaults\n<code>EnableCaseInsensitive = true<\/code> when creating a new instance of <code>ODataUriResolver<\/code>:\n<a href=\"https:\/\/github.com\/OData\/odata.net\/blob\/95233fc\/src\/Microsoft.OData.Core\/UriParser\/Resolver\/ODataUriResolver.cs#L24\">ODataUriResolver.cs<\/a><\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">private static readonly ODataUriResolver Default = new ODataUriResolver(); \/\/ EnableCaseInsensitive is now true by default<\/code><\/pre>\n<h4>Example<\/h4>\n<p>With this change, query option names are parsed equivalently regardless of casing. For instance, both of the following\nrequests now succeed and are interpreted the same way:<\/p>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">GET https:\/\/localhost:54001\/odata\/Books?$expand=Authors<\/code><\/pre>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">GET https:\/\/localhost:54001\/odata\/Books?$expand=authors<\/code><\/pre>\n<h4>Benefits<\/h4>\n<ul>\n<li><strong>Spec compliance<\/strong>: Matches the OData V4.01 requirement.<\/li>\n<li><strong>Consistency<\/strong>: Aligns ODL behavior with ASP.NET Core OData defaults.<\/li>\n<li><strong>Developer experience<\/strong>: Eliminates common case-sensitivity pitfalls in query construction.<\/li>\n<\/ul>\n<\/section>\n<section>\n<h3>Improved CSDL Type Name Validation<\/h3>\n<p>ODL now performs stricter validation of type names when parsing CSDL documents. This ensures that only valid type names\nare accepted and that clear, consistent error messages are produced when invalid cases are encountered.<\/p>\n<p>The updated logic rejects malformed or unsupported type names, closing gaps where previously invalid inputs could slip through silently.<\/p>\n<h4>What Changed<\/h4>\n<p>Validation checks have been enhanced to catch issues such as:<\/p>\n<ul>\n<li>Unmatched or misplaced parentheses\n<ul>\n<li><code>ns.myType)<\/code><\/li>\n<li><code>Collection(ns.myType<\/code><\/li>\n<li><code>(ns.myType<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Unsupported type prefixes\n<ul>\n<li><code>Enumerable(ns.myType)<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Invalid suffixes or extra characters\n<ul>\n<li><code>Collection(ns.myType)s<\/code><\/li>\n<li><code>Collection)ns.myType()<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Empty or whitespace-only type names<\/li>\n<li>Invalid use of <code>Collection<\/code> or <code>Ref<\/code>\n<ul>\n<li>Collection()<\/li>\n<li>Ref<\/li>\n<li>Ref()<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4>Why It Matters<\/h4>\n<ul>\n<li><strong>Correctness<\/strong>: Prevents invalid EDM models from being accepted, which could otherwise cause subtle runtime issues.<\/li>\n<li><strong>Clarity<\/strong>: Developers get clear, actionable error messages instead of confusing parsing behavior.<\/li>\n<li><strong>Interoperability<\/strong>: Ensures models parsed by ODL conform more strictly to OData CSDL standards, improving tooling and ecosystem alignment.<\/li>\n<\/ul>\n<\/section>\n<section>\n<h3>Removed Deprecated Flags and Properties<\/h3>\n<h4>KeyComparisonGeneratesFilterQuery<\/h4>\n<p>In ODL 9 we removed the <code>DataServiceContext.KeyComparisonGeneratesFilterQuery<\/code> flag entirely. The OData .NET\nClient now always translates a LINQ <code>Where<\/code> that compares key properties into a <code>$filter<\/code> query,\nand it reserves the <strong>key segment<\/strong> form for explicit <code>ByKey(...)<\/code> calls.<\/p>\n<h5>What Changed<\/h5>\n<p>Historically, if you had the expression:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">\/\/ Single-key entity\r\nDataServiceContextInstance.Customers.Where(c =&gt; c.Id == 13)<\/code><\/pre>\n<p>where <code>Id<\/code> is the key property, the client would emit a key segment URL:<\/p>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">\/Customers(13)<\/code><\/pre>\n<p>instead of the natural filter form:<\/p>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">\/Customers?$filter=Id eq 13<\/code><\/pre>\n<p>This would happen so long as the properties referenced in the <code>Where<\/code> expression predicate comprised of only key properties.<\/p>\n<h5>Why This Matters<\/h5>\n<p>The inconsistent behavior meant that a simple <code>Where<\/code> could silently depend on a &#8220;get-by-key&#8221; executable\nendpoint on the server (e.g., <code>Get(int key)<\/code>), while in other cases it wouldn\u2019t \u2014 an inconsistency that\nsurprised developers and produced hard-to-diagnose bugs.<\/p>\n<p>This overlap created confusion because <code>Where<\/code> is <em>naturally<\/em> a filtering operation and should translate to <code>$filter<\/code>.<\/p>\n<p>The canonical way to express \u201cget-by-key\u201d semantics has always been through the dedicated <code>ByKey<\/code> API.<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">\/\/ ByKey semantics require a dedicated get-by-key endpoint\r\n[EnableQuery]\r\npublic ActionResult&lt;Customer&gt; Get(int key) { ... }\r\n\r\n\/\/ Whereas $filter works fine with a queryable Get endpoint\r\n[EnableQuery]\r\npublic ActionResult&lt;IQueryable&lt;Customer&gt;&gt; Get() { ... }<\/code><\/pre>\n<p>By enforcing the distinction, ODL avoids subtle bugs and makes it explicit when a key-based endpoint is required.\nDevelopers upgrading from 8.x should review their LINQ queries to ensure that any intended key lookups use <code>ByKey<\/code> explicitly.<\/p>\n<h5>Deprecation Path<\/h5>\n<ul>\n<li><strong>ODL 7.x<\/strong>: Introduced the <code>KeyComparisonGeneratesFilterQuery<\/code> flag (default: <code>false<\/code>) to avoid an immediate breaking change.<\/li>\n<li><strong>ODL 8.x<\/strong>: Changed the default to <code>true<\/code>, so <code>Where<\/code> expressions would generate <code>$filter<\/code> unless explicitly toggled back.<\/li>\n<li><strong>ODL 9.x<\/strong>: Removed the flag entirely. Developers must now use <code>ByKey<\/code> for key lookups, and <code>Where<\/code> will consistently generate <code>$filter<\/code>.<\/li>\n<\/ul>\n<h5>Benefits<\/h5>\n<ul>\n<li><strong>Clarity<\/strong>: Developers know exactly when they\u2019re generating <code>ByKey<\/code> versus <code>$filter<\/code> queries.<\/li>\n<li><strong>Consistency<\/strong>: Eliminates situations where the same LINQ query might require different service endpoints.<\/li>\n<li><strong>Correctness<\/strong>: Prevents hidden coupling between query translation and service controller design.<\/li>\n<\/ul>\n<h4>Timeout Property<\/h4>\n<p>The obsolete <code>DataServiceContext.Timeout<\/code> property has been fully removed. As recommended since 8.x, configure\ntimeouts on your <code>HttpClient<\/code> via <code>IHttpClientFactory<\/code> and related handlers, rather than on the\nOData client surface. This keeps HTTP concerns in the HTTP layer and aligns with modern .NET guidance and our 8.x\ndeprecation notes<\/p>\n<\/section>\n<section>\n<h3>Reduced Redundant Payload Annotations<\/h3>\n<p>When generating payloads, the OData client would serialize <code>@odata.type<\/code> annotations even for\n<strong>declared properties<\/strong> and non-derived instances. While technically valid, these annotations inflated payload\nsizes and added noise without providing additional value.<\/p>\n<h4>Example<\/h4>\n<p>Consider an Order entity with declared properties like <code>Status<\/code>, <code>Tags<\/code>, and <code>ShippingAddress<\/code>. Previously, serializing such an entity in OData client produced redundant annotations:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"@odata.type\": \"#Ns.Models.Order\",\r\n  \"Id\": 1,\r\n  \"Status@odata.type\": \"#Ns.Models.OrderStatus\",\r\n  \"Status\": \"Pending\",\r\n  \"Tags@odata.type\": \"#Collection(String)\",\r\n  \"Tags\": [\"Urgent\"],\r\n  \"ShippingAddress\": {\r\n    \"@odata.type\": \"#Ex340.Models.Address\",\r\n    \"Street\": \"123 Main St\"\r\n  }\r\n}<\/code><\/pre>\n<p>Here, the annotations are unnecessary because:<\/p>\n<ul>\n<li><code>Status<\/code> is a declared enum property.<\/li>\n<li><code>Tags<\/code> is a declared collection of strings.<\/li>\n<li><code>ShippingAddress<\/code> is a declared complex type.<\/li>\n<\/ul>\n<h4>What Changed<\/h4>\n<p>With ODL 9, these redundant <code>@odata.type<\/code> annotations are <strong>omitted<\/strong> unless:<\/p>\n<ul>\n<li>The instance is of a derived type, or<\/li>\n<li>The property is dynamic (not declared in metadata).<\/li>\n<\/ul>\n<p>The same payload is now serialized much more concisely:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"Id\": 1,\r\n  \"Status\": \"Pending\",\r\n  \"Tags\": [\"Urgent\"],\r\n  \"ShippingAddress\": {\r\n    \"Street\": \"123 Main St\"\r\n  }\r\n}<\/code><\/pre>\n<h4>Benefits<\/h4>\n<ul>\n<li><strong>Smaller payloads<\/strong>: Reduced bandwidth usage and faster responses.<\/li>\n<li><strong>Cleaner JSON<\/strong>: Easier to read, debug, and consume.<\/li>\n<li><strong>Correctness preserved<\/strong>: Annotations still appear when needed for derived or dynamic values.<\/li>\n<\/ul>\n<\/section>\n<section>\n<h3>Removed Support for Nullable Generic Key Types<\/h3>\n<p>In earlier versions of the OData client, there was a bug that allowed <strong>nullable properties<\/strong> to be\ndesignated as key properties in an entity type definition. For example:<\/p>\n<pre class=\"prettyprint language-cs\"><code class=\"language-cs\">public class Person\r\n{\r\n    public int? PersonId { get; set; }  \/\/ Nullable key (incorrectly allowed)\r\n    public string Name { get; set; }\r\n}<\/code><\/pre>\n<h4>Why This Was a Problem<\/h4>\n<ul>\n<li><strong>Violation of the OData spec<\/strong>: Entity keys must always be non-nullable. A <code>null<\/code> key would make the identity of the entity undefined.<\/li>\n<li><strong>Potential runtime errors<\/strong>: Nullable keys could lead to invalid URIs or unpredictable server behavior.<\/li>\n<li><strong>Silent inconsistency<\/strong>: Since OData client didn\u2019t enforce correctness, developers could model data in ways that would later fail when interacting with an OData service.<\/li>\n<\/ul>\n<h4>Why the Fix Landed in ODL 9<\/h4>\n<p>Correcting this in a minor version would have been a <strong>breaking change<\/strong>, since previously accepted models would suddenly fail validation.\nTo avoid disrupting existing consumers in patch or minor releases, the fix was deferred until ODL 9, where breaking changes are expected.<\/p>\n<h4>Benefits<\/h4>\n<ul>\n<li><strong>Correctness<\/strong>: Ensures entity keys comply with the OData specification.<\/li>\n<li><strong>Predictability<\/strong>: Eliminates undefined edge cases caused by nullable keys.<\/li>\n<li><strong>Clarity<\/strong>: Developers now get clear validation errors if they attempt to use a nullable key property.<\/li>\n<\/ul>\n<\/section>\n<section>\n<h3>Custom URI Extensions Registered per EDM Model<\/h3>\n<p>Another significant change in ODL 9 is how <strong>custom URI functions, literal prefixes, and literal parsers<\/strong>\nare registered. Previously, these were registered globally using static helpers:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">CustomUriLiteralPrefixes.AddCustomLiteralPrefix(\"temp\", EdmCoreModel.Instance.GetDouble(false));\r\nCustomUriLiteralParsers.AddCustomUriLiteralParser(EdmCoreModel.Instance.GetDouble(false), new TemperatureUriLiteralParser());\r\nCustomUriFunctions.AddCustomUriFunction(\r\n    \"tofahrenheit\",\r\n    new FunctionSignatureWithReturnType(\r\n        EdmCoreModel.Instance.GetDouble(false),\r\n        EdmCoreModel.Instance.GetDouble(false)));<\/code><\/pre>\n<p>This global registration caused problems for multi-model scenarios, where different EDM models might require different\nsets of extensions.<\/p>\n<h4>What Changed<\/h4>\n<p>In ODL 9, these are now registered <strong>per EDM model<\/strong> instead of globally. This improves isolation, avoids\nunintended conflicts, and gives fine-grained control.<\/p>\n<p>For example:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">var modelBuilder = new ODataConventionModelBuilder();\r\nmodelBuilder.EntitySet&lt;Weather&gt;(\"WeatherForecast\");\r\nvar model = modelBuilder.GetEdmModel();\r\n\/\/ Register extensions per model\r\nmodel.AddCustomLiteralPrefix(\"temp\", EdmCoreModel.Instance.GetDouble(false));\r\nmodel.AddCustomUriLiteralParser(EdmCoreModel.Instance.GetDouble(false), new TemperatureUriLiteralParser());\r\nmodel.AddCustomUriFunction(\r\n    \"tofahrenheit\",\r\n    new FunctionSignatureWithReturnType(\r\n        EdmCoreModel.Instance.GetDouble(false),\r\n        EdmCoreModel.Instance.GetDouble(false)));<\/code><\/pre>\n<ul>\n<li><strong>Custom URI Functions<\/strong>: Extend OData query semantics by adding custom functions usable in <code>$filter<\/code>, <code>$orderby<\/code>, etc. (e.g., converting Celsius to Fahrenheit).<\/li>\n<li><strong>Custom URI Literal Prefixes<\/strong>: Allow introducing new literal formats (e.g., <code>temp'79.7:Fahrenheit'<\/code>).<\/li>\n<li><strong>Custom URI Literal Parsers<\/strong>: Implement logic to parse and interpret these custom literals into CLR values.<\/li>\n<\/ul>\n<h4>Example in Action<\/h4>\n<p>Custom URI function usage:<\/p>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">GET http:\/\/localhost\/WeatherForecast?$filter=tofahrenheit(Temperature) gt 70<\/code><\/pre>\n<p>Custom URI literal usage:<\/p>\n<pre class=\"prettyprint language-http\"><code class=\"language-http\">GET http:\/\/localhost\/WeatherForecast?$filter=Temperature eq temp'79.7:Fahrenheit'<\/code><\/pre>\n<h4>Benefits<\/h4>\n<ul>\n<li><strong>Isolation<\/strong>: Different models can have different custom functions and literals without clashing.<\/li>\n<li><strong>Flexibility<\/strong>: Enables richer, domain-specific query expressions.<\/li>\n<li><strong>Cleaner design<\/strong>: No more static\/global state; behavior is tied to the model where it belongs.<\/li>\n<\/ul>\n<\/section>\n<h2>Summary<\/h2>\n<p>The ODL 9 previews bring meaningful updates:<\/p>\n<ul>\n<li>Modern runtime support (targeting .NET 10).<\/li>\n<li>Removal of outdated features (JSONP, deprecated properties\/flags).<\/li>\n<li>Usability improvements (case-insensitive resolver by default, reduced payload noise).<\/li>\n<li>More robust model-specific approach to custom URI functions, prefixes, and parsers.<\/li>\n<\/ul>\n<p>These changes pave the way for a cleaner, more predictable OData experience moving forward. In future updates, we\u2019ll\nprovide deeper examples and migration guidance for developers upgrading to ODL 9.<\/p>\n<p>Try the ODL 9 preview packages on NuGet and share feedback on\n<a href=\"https:\/\/github.com\/OData\/odata.net\/issues\">GitHub repo<\/a>.<\/p>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>We\u2019re happy to announce that OData .NET (ODL) 9 Preview 2 has been officially released and is available on NuGet: Microsoft.OData.Core 9.0.0 Preview 2 Microsoft.OData.Edm 9.0.0 Preview 2 Microsoft.Spatial 9.0.0 Preview 2 Microsoft.OData.Client 9.0.0 Preview 2 What\u2019s New in OData .NET (ODL) 9 Preview 1 &amp; 2 The OData .NET (ODL) 9.0 previews introduce a [&hellip;]<\/p>\n","protected":false},"author":25333,"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-5892","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata"],"acf":[],"blog_post_summary":"<p>We\u2019re happy to announce that OData .NET (ODL) 9 Preview 2 has been officially released and is available on NuGet: Microsoft.OData.Core 9.0.0 Preview 2 Microsoft.OData.Edm 9.0.0 Preview 2 Microsoft.Spatial 9.0.0 Preview 2 Microsoft.OData.Client 9.0.0 Preview 2 What\u2019s New in OData .NET (ODL) 9 Preview 1 &amp; 2 The OData .NET (ODL) 9.0 previews introduce a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/5892","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\/25333"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=5892"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/5892\/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=5892"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=5892"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=5892"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}